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), 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 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, 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, 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  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  rates.push_back(32000);
121  rates.push_back(44100);
122  rates.push_back(48000);
123 
124  allowed_rate[48000] = true;
125  for (uint i = 0; analog && (i < rates.size()); i++)
126  allowed_rate[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 < rates.size(); i++)
137  {
138  if (allowed_rate[rates[i]])
139  addSelection(QString::number(rates[i]));
140  }
141 
142  int which = getValueIndex(val);
143  setValue(max(which,0));
144 
145  if (allowed_rate.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 (allowed_rate[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> rates;
168  QMap<uint,bool> allowed_rate;
169 };
170 
172 {
173  public:
175  bool layer1, bool layer2, bool layer3) :
176  MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "mpeg2audtype"),
177  allow_layer1(layer1), allow_layer2(layer2), allow_layer3(layer3)
178  {
179  setLabel(QObject::tr("Type"));
180 
181  if (allow_layer1)
182  addSelection("Layer I");
183  if (allow_layer2)
184  addSelection("Layer II");
185  if (allow_layer3)
186  addSelection("Layer III");
187 
188  uint allowed_cnt = 0;
189  allowed_cnt += ((allow_layer1) ? 1 : 0);
190  allowed_cnt += ((allow_layer2) ? 1 : 0);
191  allowed_cnt += ((allow_layer3) ? 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") && !allow_layer1)
205  {
206  val = (allow_layer2) ? "Layer II" :
207  ((allow_layer3) ? "Layer III" : val);
208  }
209 
210  if ((val == "Layer II") && !allow_layer2)
211  {
212  val = (allow_layer3) ? "Layer III" :
213  ((allow_layer1) ? "Layer I" : val);
214  }
215 
216  if ((val == "Layer III") && !allow_layer3)
217  {
218  val = (allow_layer2) ? "Layer II" :
219  ((allow_layer1) ? "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  MPEG2audType *audType = new MPEG2audType(
346  parent, layer1, layer2, layer3);
347 
348  addChild(audType);
349 
350  addTargetedChild(layers[0], new MPEG2audBitrateL1(parent));
351  addTargetedChild(layers[1], new MPEG2audBitrateL2(parent));
352  addTargetedChild(layers[2], new MPEG2audBitrateL3(parent));
353 
354  uint desired_layer = max(min(3U, default_layer), 1U) - 1;
355  int which = audType->getValueIndex(layers[desired_layer]);
356  if (which >= 0)
357  audType->setValue(which);
358  };
359 };
360 
362 {
363  public:
364  explicit MPEG2Language(const RecordingProfile &parent) :
365  MythUIComboBoxSetting(this), CodecParamStorage(this, parent, "mpeg2language")
366  {
367  setLabel(QObject::tr("SAP/Bilingual"));
368 
369  addSelection(QObject::tr("Main Language"), "0");
370  addSelection(QObject::tr("SAP Language"), "1");
371  addSelection(QObject::tr("Dual"), "2");
372 
373  setValue(0);
374  setHelpText(QObject::tr(
375  "Chooses the language(s) to record when "
376  "two languages are broadcast. Only Layer II "
377  "supports the recording of two languages (Dual)."
378  "Requires ivtv 0.4.0 or later."));
379  };
380 };
381 
383 {
384  public:
386  QString setting = "mpeg2bitratemode") :
387  MythUIComboBoxSetting(this),
388  CodecParamStorage(this, parent, std::move(setting))
389  {
390  setLabel(QObject::tr("Bitrate Mode"));
391 
392  addSelection("Variable Bitrate", "0");
393  addSelection("Constant Bitrate", "1");
394  setValue(0);
395  setHelpText(QObject::tr("Bitrate mode"));
396  }
397 };
398 
400 {
401  public:
403  V4L2util* v4l2) :
404  m_parent(parentProfile)
405  {
406  setName(QObject::tr("Audio Quality"));
407 
410 
411  QString label("MP3");
415 
416  label = "MPEG-2 Hardware Encoder";
417  m_codecName->addTargetedChild(label, new SampleRate(m_parent, false));
420  (m_parent, false, true, false, 2));
423 
424  label = "Uncompressed";
427 
428  m_codecName->addTargetedChild("AC3 Hardware Encoder",
429  new GroupSetting());
430 
431  m_codecName->addTargetedChild("AAC Hardware Encoder",
432  new GroupSetting());
433 
434 #ifdef USING_V4L2
435  if (v4l2)
436  {
437  // Dynamically create user options based on the
438  // capabilties the driver reports.
439 
440  DriverOption::Options options;
441 
442  if (v4l2->GetOptions(options))
443  {
444  /* StandardSetting cannot handle multiple 'targets' pointing
445  * to the same setting configuration, so we need to do
446  * this in two passes. */
447 
448  for (auto Iopt = options.begin(); Iopt != options.end(); ++Iopt)
449  {
450  if ((*Iopt).m_category == DriverOption::AUDIO_ENCODING)
451  {
452  DriverOption::menu_t::iterator Imenu =
453  (*Iopt).m_menu.begin();
454  for ( ; Imenu != (*Iopt).m_menu.end(); ++Imenu)
455  {
456  if (!(*Imenu).isEmpty())
457  m_v4l2codecs << "V4L2:" + *Imenu;
458  }
459  }
460  }
461 
462  QStringList::iterator Icodec = m_v4l2codecs.begin();
463  for ( ; Icodec < m_v4l2codecs.end(); ++Icodec)
464  {
465  for (auto Iopt = options.begin(); Iopt != options.end(); ++Iopt)
466  {
467  if ((*Iopt).m_category == DriverOption::AUDIO_BITRATE_MODE)
468  {
469  m_codecName->addTargetedChild(*Icodec,
470  new BitrateMode(m_parent, "audbitratemode"));
471  }
472  else if ((*Iopt).m_category ==
474  {
475  m_codecName->addTargetedChild(*Icodec,
476  new SampleRate(m_parent, false));
477  }
478  else if ((*Iopt).m_category ==
480  {
481  m_codecName->addTargetedChild(*Icodec,
482  new MPEG2Language(m_parent));
483  }
484  else if ((*Iopt).m_category == DriverOption::AUDIO_BITRATE)
485  {
486  bool layer1, layer2, layer3;
487  layer1 = layer2 = 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:
768  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, std::move(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:
789  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, std::move(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:
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:
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  GroupSetting *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  GroupSetting *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  GroupSetting *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  {
982  DriverOption::Options options;
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  GroupSetting* bit_low = new GroupSetting();
1008  GroupSetting* bit_medium = new GroupSetting();
1009  GroupSetting* 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_default_value));
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_default_value));
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_default_value / 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_default_value / 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_default_value / 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_default_value / 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_default_value / 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_default_value / 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_default_value / 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_default_value / 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), maxsize(768, 576);
1346  bool transcoding = profName.startsWith("Transcoders");
1347  bool ivtv = profName.startsWith("IVTV MPEG-2 Encoders");
1348 
1349  if (transcoding)
1350  {
1351  maxsize = QSize(1920, 1088);
1352  if (tvFormat.toLower() == "ntsc" || tvFormat.toLower() == "atsc")
1353  defaultsize = QSize(480, 480);
1354  else
1355  defaultsize = QSize(480, 576);
1356  }
1357  else if (tvFormat.toLower().startsWith("ntsc"))
1358  {
1359  maxsize = QSize(720, 480);
1360  defaultsize = (ivtv) ? QSize(720, 480) : QSize(480, 480);
1361  }
1362  else if (tvFormat.toLower() == "atsc")
1363  {
1364  maxsize = QSize(1920, 1088);
1365  defaultsize = QSize(1920, 1088);
1366  }
1367  else
1368  {
1369  maxsize = QSize(768, 576);
1370  defaultsize = (ivtv) ? QSize(720, 576) : QSize(480, 576);
1371  }
1372 
1373  addChild(new Width(parent, defaultsize.width(),
1374  maxsize.width(), transcoding));
1375  addChild(new Height(parent, defaultsize.height(),
1376  maxsize.height(), transcoding));
1377  };
1378 };
1379 
1380 // id and name will be deleted by ConfigurationGroup's destructor
1381 RecordingProfile::RecordingProfile(const QString& profName)
1382  : m_id(new ID()),
1383  m_name(new Name(*this)),
1384  m_profileName(profName)
1385 {
1386  // This must be first because it is needed to load/save the other settings
1387  addChild(m_id);
1388 
1389  setLabel(profName);
1390  addChild(m_name);
1391 
1392  m_trFilters = nullptr;
1393  m_trLossless = nullptr;
1394  m_trResize = nullptr;
1395 
1396  if (!profName.isEmpty())
1397  {
1398  if (profName.startsWith("Transcoders"))
1399  {
1400  m_trFilters = new TranscodeFilters(*this);
1401  m_trLossless = new TranscodeLossless(*this);
1402  m_trResize = new TranscodeResize(*this);
1403  addChild(m_trFilters);
1404  addChild(m_trLossless);
1405  addChild(m_trResize);
1406  }
1407  else
1408  addChild(new AutoTranscode(*this));
1409  }
1410  else
1411  {
1412  m_trFilters = new TranscodeFilters(*this);
1413  m_trLossless = new TranscodeLossless(*this);
1414  m_trResize = new TranscodeResize(*this);
1415  addChild(m_trFilters);
1416  addChild(m_trLossless);
1417  addChild(m_trResize);
1418  addChild(new AutoTranscode(*this));
1419  }
1420 };
1421 
1423 {
1424 #ifdef USING_V4L2
1425  delete m_v4l2util;
1426  m_v4l2util = nullptr;
1427 #endif
1428 }
1429 
1430 void RecordingProfile::ResizeTranscode(const QString & /*val*/)
1431 {
1432  if (m_imageSize)
1433  m_imageSize->setEnabled(m_trResize->boolValue());
1434 }
1435 
1436 void RecordingProfile::SetLosslessTranscode(const QString & /*val*/)
1437 {
1438  bool lossless = m_trLossless->boolValue();
1439  bool show_size = (lossless) ? false : m_trResize->boolValue();
1440  if (m_imageSize)
1441  m_imageSize->setEnabled(show_size);
1442  m_videoSettings->setEnabled(! lossless);
1443  m_audioSettings->setEnabled(! lossless);
1444  m_trResize->setEnabled(! lossless);
1445  m_trFilters->setEnabled(! lossless);
1446 }
1447 
1448 void RecordingProfile::loadByID(int profileId)
1449 {
1450  MSqlQuery result(MSqlQuery::InitCon());
1451  result.prepare(
1452  "SELECT cardtype, profilegroups.name "
1453  "FROM profilegroups, recordingprofiles "
1454  "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1455  " recordingprofiles.id = :PROFILEID");
1456  result.bindValue(":PROFILEID", profileId);
1457 
1458  QString type;
1459  QString name;
1460  if (!result.exec())
1461  {
1462  MythDB::DBError("RecordingProfile::loadByID -- cardtype", result);
1463  }
1464  else if (result.next())
1465  {
1466  type = result.value(0).toString();
1467  name = result.value(1).toString();
1468  }
1469 
1470  CompleteLoad(profileId, type, name);
1471 }
1472 
1473 void RecordingProfile::FiltersChanged(const QString &val)
1474 {
1475  // If there are filters, we cannot do lossless transcoding
1476  if (!val.trimmed().isEmpty())
1477  {
1478  m_trLossless->setValue(false);
1479  m_trLossless->setEnabled(false);
1480  }
1481  else
1482  {
1483  m_trLossless->setEnabled(true);
1484  }
1485 }
1486 
1487 bool RecordingProfile::loadByType(const QString &name, const QString &card,
1488  const QString &videodev)
1489 {
1490  QString hostname = gCoreContext->GetHostName().toLower();
1491  QString cardtype = card;
1492  uint profileId = 0;
1493 
1494 #ifdef USING_V4L2
1495  if (cardtype == "V4L2ENC")
1496  {
1497  m_v4l2util = new V4L2util(videodev);
1498  if (m_v4l2util->IsOpen())
1499  cardtype = m_v4l2util->ProfileName();
1500  }
1501 #else
1502  Q_UNUSED(videodev);
1503 #endif
1504 
1505  MSqlQuery result(MSqlQuery::InitCon());
1506  result.prepare(
1507  "SELECT recordingprofiles.id, profilegroups.hostname, "
1508  " profilegroups.is_default "
1509  "FROM recordingprofiles, profilegroups "
1510  "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1511  " profilegroups.cardtype = :CARDTYPE AND "
1512  " recordingprofiles.name = :NAME");
1513  result.bindValue(":CARDTYPE", cardtype);
1514  result.bindValue(":NAME", name);
1515 
1516  if (!result.exec())
1517  {
1518  MythDB::DBError("RecordingProfile::loadByType()", result);
1519  return false;
1520  }
1521 
1522  while (result.next())
1523  {
1524  if (result.value(1).toString().toLower() == hostname)
1525  {
1526  profileId = result.value(0).toUInt();
1527  }
1528  else if (result.value(2).toInt() == 1)
1529  {
1530  profileId = result.value(0).toUInt();
1531  break;
1532  }
1533  }
1534 
1535  if (profileId)
1536  {
1537  CompleteLoad(profileId, cardtype, name);
1538  return true;
1539  }
1540 
1541  return false;
1542 }
1543 
1544 bool RecordingProfile::loadByGroup(const QString &name, const QString &group)
1545 {
1546  MSqlQuery result(MSqlQuery::InitCon());
1547  result.prepare(
1548  "SELECT recordingprofiles.id, cardtype "
1549  "FROM recordingprofiles, profilegroups "
1550  "WHERE recordingprofiles.profilegroup = profilegroups.id AND "
1551  " profilegroups.name = :GROUPNAME AND "
1552  " recordingprofiles.name = :NAME");
1553  result.bindValue(":GROUPNAME", group);
1554  result.bindValue(":NAME", name);
1555 
1556  if (!result.exec())
1557  {
1558  MythDB::DBError("RecordingProfile::loadByGroup()", result);
1559  return false;
1560  }
1561 
1562  if (result.next())
1563  {
1564  uint profileId = result.value(0).toUInt();
1565  QString type = result.value(1).toString();
1566 
1567  CompleteLoad(profileId, type, name);
1568  return true;
1569  }
1570 
1571  return false;
1572 }
1573 
1574 void RecordingProfile::CompleteLoad(int profileId, const QString &type,
1575  const QString &name)
1576 {
1577  if (m_profileName.isEmpty())
1578  m_profileName = name;
1579 
1581 
1582  if (m_isEncoder)
1583  {
1584 #ifdef USING_V4L2
1585  if (type.startsWith("V4L2:"))
1586  {
1587  QStringList devices = CardUtil::GetVideoDevices("V4L2ENC");
1588  if (!devices.isEmpty())
1589  {
1590  QStringList::iterator Idev = devices.begin();
1591  for ( ; Idev != devices.end(); ++Idev)
1592  {
1593  delete m_v4l2util;
1594  m_v4l2util = new V4L2util(*Idev);
1595  if (m_v4l2util->IsOpen() &&
1596  m_v4l2util->DriverName() == type.mid(5))
1597  break;
1598  delete m_v4l2util;
1599  m_v4l2util = nullptr;
1600  }
1601  }
1602  }
1603 #endif
1604 
1605  QString tvFormat = gCoreContext->GetSetting("TVFormat");
1606  // TODO: When mpegrecorder is removed, don't check for "HDPVR' anymore...
1607  if (type != "HDPVR" &&
1608  (!m_v4l2util
1609 #ifdef USING_V4L2
1611 #endif
1612  ))
1613  {
1614  addChild(new ImageSize(*this, tvFormat, m_profileName));
1615  }
1617  m_v4l2util);
1619 
1621  m_v4l2util);
1623 
1624  if (!m_profileName.isEmpty() && m_profileName.startsWith("Transcoders"))
1625  {
1626  connect(m_trResize, SIGNAL(valueChanged (const QString &)),
1627  this, SLOT( ResizeTranscode(const QString &)));
1628  connect(m_trLossless, SIGNAL(valueChanged (const QString &)),
1629  this, SLOT( SetLosslessTranscode(const QString &)));
1630  connect(m_trFilters, SIGNAL(valueChanged(const QString&)),
1631  this, SLOT(FiltersChanged(const QString&)));
1632  }
1633  }
1634  else if (type.toUpper() == "DVB")
1635  {
1636  addChild(new RecordingType(*this));
1637  }
1638 
1640  {
1641  addChild(new RecordFullTSStream(*this));
1642  }
1643 
1644  m_id->setValue(profileId);
1645  Load();
1646 }
1647 
1649 {
1650  if (m_videoSettings)
1652  if (m_audioSettings)
1654 }
1655 
1656 RecordingProfileEditor::RecordingProfileEditor(int id, QString profName) :
1657  group(id), labelName(std::move(profName))
1658 {
1659  if (!labelName.isEmpty())
1660  setLabel(labelName);
1661 }
1662 
1664 {
1665  clearSettings();
1666  ButtonStandardSetting *newProfile =
1667  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  MythTextInputDialog *settingdialog =
1678  new MythTextInputDialog(popupStack,
1679  tr("Enter the name of the new profile"));
1680 
1681  if (settingdialog->Create())
1682  {
1683  connect(settingdialog, SIGNAL(haveResult(QString)),
1684  SLOT(CreateNewProfile(QString)));
1685  popupStack->AddScreen(settingdialog);
1686  }
1687  else
1688  {
1689  delete settingdialog;
1690  }
1691 }
1692 
1693 void RecordingProfileEditor::CreateNewProfile(const QString& profName)
1694 {
1695  MSqlQuery query(MSqlQuery::InitCon());
1696  query.prepare(
1697  "INSERT INTO recordingprofiles "
1698  "(name, videocodec, audiocodec, profilegroup) "
1699  "VALUES "
1700  "(:NAME, :VIDEOCODEC, :AUDIOCODEC, :PROFILEGROUP);");
1701  query.bindValue(":NAME", profName);
1702  query.bindValue(":VIDEOCODEC", "MPEG-4");
1703  query.bindValue(":AUDIOCODEC", "MP3");
1704  query.bindValue(":PROFILEGROUP", group);
1705  if (!query.exec())
1706  {
1707  MythDB::DBError("RecordingProfileEditor::open", query);
1708  }
1709  else
1710  {
1711  query.prepare(
1712  "SELECT id "
1713  "FROM recordingprofiles "
1714  "WHERE name = :NAME AND profilegroup = :PROFILEGROUP;");
1715  query.bindValue(":NAME", profName);
1716  query.bindValue(":PROFILEGROUP", group);
1717  if (!query.exec())
1718  {
1719  MythDB::DBError("RecordingProfileEditor::open", query);
1720  }
1721  else
1722  {
1723  if (query.next())
1724  {
1725  RecordingProfile* profile = new RecordingProfile(profName);
1726 
1727  profile->loadByID(query.value(0).toInt());
1728  profile->setCodecTypes();
1729  addChild(profile);
1730  emit settingsChanged(this);
1731  }
1732  }
1733  }
1734 }
1735 
1736 void RecordingProfile::fillSelections(GroupSetting *setting, int group,
1737  bool foldautodetect)
1738 {
1739  if (!group)
1740  {
1741  for (uint i = 0; !availProfiles[i].isEmpty(); i++)
1742  {
1744  profile->setLabel(availProfiles[i]);
1745  setting->addChild(profile);
1746  }
1747  return;
1748  }
1749 
1750  MSqlQuery result(MSqlQuery::InitCon());
1751  result.prepare(
1752  "SELECT name, id "
1753  "FROM recordingprofiles "
1754  "WHERE profilegroup = :GROUP "
1755  "ORDER BY id");
1756  result.bindValue(":GROUP", group);
1757 
1758  if (!result.exec())
1759  {
1760  MythDB::DBError("RecordingProfile::fillSelections 1", result);
1761  return;
1762  }
1763  if (!result.next())
1764  {
1765  return;
1766  }
1767 
1768  if (group == RecordingProfile::TranscoderGroup && foldautodetect)
1769  {
1770  QString id = QString::number(RecordingProfile::TranscoderAutodetect);
1772  profile->setLabel(QObject::tr("Autodetect"));
1773  setting->addChild(profile);
1774  }
1775 
1776  do
1777  {
1778  QString name = result.value(0).toString();
1779  QString id = result.value(1).toString();
1780 
1781  if (group == RecordingProfile::TranscoderGroup)
1782  {
1783  if (name == "RTjpeg/MPEG4" || name == "MPEG2")
1784  {
1785  if (!foldautodetect)
1786  {
1788  new RecordingProfile(QObject::tr("Autodetect from %1")
1789  .arg(name));
1790  profile->loadByID(id.toInt());
1791  profile->setCodecTypes();
1792  setting->addChild(profile);
1793  }
1794  }
1795  else
1796  {
1798  profile->loadByID(id.toInt());
1799  profile->setCodecTypes();
1800  setting->addChild(profile);
1801  }
1802  continue;
1803  }
1804 
1806  profile->loadByID(id.toInt());
1807  profile->setCodecTypes();
1808  setting->addChild(profile);
1809  }
1810  while (result.next());
1811 }
1812 
1813 QMap< int, QString > RecordingProfile::GetProfiles(RecProfileGroup group)
1814 {
1815  QMap<int, QString> profiles;
1816 
1817  if (!group)
1818  {
1819  for (uint i = 0; !availProfiles[i].isEmpty(); i++)
1820  profiles[i] = availProfiles[i];
1821  return profiles;
1822  }
1823 
1824  MSqlQuery query(MSqlQuery::InitCon());
1825  query.prepare(
1826  "SELECT name, id "
1827  "FROM recordingprofiles "
1828  "WHERE profilegroup = :GROUPID "
1829  "ORDER BY id");
1830  query.bindValue(":GROUPID", group);
1831 
1832  if (!query.exec())
1833  {
1834  MythDB::DBError("RecordingProfile::GetProfileMap()", query);
1835  return profiles;
1836  }
1837  if (!query.next())
1838  {
1839  LOG(VB_GENERAL, LOG_WARNING,
1840  "RecordingProfile::fillselections, Warning: "
1841  "Failed to locate recording id for recording group.");
1842  return profiles;
1843  }
1844 
1845  if (group == RecordingProfile::TranscoderGroup)
1846  {
1848  profiles[id] = QObject::tr("Transcode using Autodetect");
1849  }
1850 
1851  do
1852  {
1853  QString name = query.value(0).toString();
1854  int id = query.value(1).toInt();
1855 
1856  if (group == RecordingProfile::TranscoderGroup)
1857  {
1858  /* RTjpeg/MPEG4 and MPEG2 are used by "Autodetect". */
1859  if (name != "RTjpeg/MPEG4" && name != "MPEG2")
1860  {
1861  QString lbl = QObject::tr("Transcode using \"%1\"").arg(name);
1862  profiles[id] = lbl;
1863  }
1864  continue;
1865  }
1866 
1867  QString lbl = QObject::tr("Record using the \"%1\" profile").arg(name);
1868  profiles[id] = lbl;
1869  } while (query.next());
1870 
1871  return profiles;
1872 }
1873 
1874 QMap< int, QString > RecordingProfile::GetTranscodingProfiles()
1875 {
1877 }
1878 
1879 QString RecordingProfile::groupType(void) const
1880 {
1881  MSqlQuery result(MSqlQuery::InitCon());
1882  result.prepare(
1883  "SELECT profilegroups.cardtype "
1884  "FROM profilegroups, recordingprofiles "
1885  "WHERE profilegroups.id = recordingprofiles.profilegroup AND "
1886  " recordingprofiles.id = :ID");
1887  result.bindValue(":ID", getProfileNum());
1888 
1889  if (!result.exec())
1890  MythDB::DBError("RecordingProfile::groupType", result);
1891  else if (result.next())
1892  return result.value(0).toString();
1893 
1894  return QString();
1895 }
1896 
1897 QString RecordingProfile::getName(int id)
1898 {
1899  MSqlQuery result(MSqlQuery::InitCon());
1900  result.prepare(
1901  "SELECT name "
1902  "FROM recordingprofiles "
1903  "WHERE id = :ID");
1904 
1905  result.bindValue(":ID", id);
1906 
1907  if (!result.exec())
1908  MythDB::DBError("RecordingProfile::getName", result);
1909  else if (result.next())
1910  return result.value(0).toString();
1911 
1912  return QString();
1913 }
1914 
1915 bool RecordingProfile::canDelete(void)
1916 {
1917  return true;
1918 }
1919 
1921 {
1922  MSqlQuery result(MSqlQuery::InitCon());
1923  result.prepare(
1924  "DELETE "
1925  "FROM recordingprofiles "
1926  "WHERE id = :ID");
1927 
1928  result.bindValue(":ID", m_id->getValue());
1929 
1930  if (!result.exec())
1931  MythDB::DBError("RecordingProfile::deleteEntry", result);
1932 
1933 }
1934 
1935 
1936 /* 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)
QMap< category_t, DriverOption > Options
Definition: driveroption.h:20
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)
void Load(void) override
Definition: mythstorage.cpp:8
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)
vector< uint > rates
MPEG2audBitrateL3(const RecordingProfile &parent)
CodecParamStorage(StandardSetting *_setting, const RecordingProfile &parentProfile, const QString &name)
MythScreenStack * GetStack(const QString &stackname)
MPEG4OptionIDCT(const RecordingProfile &parent)
unsigned int uint
Definition: compat.h:140
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
QString ProfileName(void) const
Definition: v4l2util.h:47
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)
enum RecordingTypes RecordingType
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)
bool Create(void) override
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
MPEG4OptionIME(const RecordingProfile &parent)
AverageBitrate(const RecordingProfile &parent, QString setting="mpeg2bitrate", uint min_br=1000, uint max_br=16000, uint default_br=4500, uint increment=100, QString label=QString())
QMap< uint, bool > allowed_rate
void setValue(int value) override
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
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
RecordingProfileEditor(int id, QString profName)
const char * name
Definition: ParseText.cpp:328
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)
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)
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
PeakBitrate(const RecordingProfile &parent, QString setting="mpeg2maxbitrate", uint min_br=1000, uint max_br=16000, uint default_br=6000, uint increment=100, QString label=QString())
void setValue(const QString &) override
bool canDelete(void) override
TranscodeResize * m_trResize
MPEG2audBitrateL1(const RecordingProfile &parent)
const QString availProfiles[]
virtual void loadByID(int id)
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:98
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:45
virtual void setValue(const QString &newValue)
BitrateMode(const RecordingProfile &parent, QString setting="mpeg2bitratemode")
virtual bool loadByType(const QString &name, const QString &cardtype, const QString &videodev)
HardwareMJPEGHDecimation(const RecordingProfile &parent)
void valueChanged(const QString &)