MythTV  master
mpegrecorder.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // C++ headers
4 #include <algorithm>
5 #include <chrono> // for milliseconds
6 #include <cinttypes>
7 #include <ctime>
8 #include <fcntl.h>
9 #include <thread> // for sleep_for
10 #include <unistd.h>
11 #include <vector>
12 
13 // System headers
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/ioctl.h>
17 #include <sys/time.h>
18 #include <sys/poll.h>
19 
20 #include <linux/videodev2.h>
21 
22 #include "libmythbase/mythconfig.h"
23 
24 // MythTV headers
26 #include "libmythbase/mythdate.h"
29 
30 #include "cardutil.h"
31 #include "io/mythmediabuffer.h"
32 #include "mpegrecorder.h"
33 #include "recordingprofile.h"
34 #include "tv_rec.h"
35 
36 #define LOC QString("MPEGRec[%1](%2): ") \
37  .arg(m_tvrec ? m_tvrec->GetInputId() : -1).arg(m_videodevice)
38 
39 const std::array<const int,14> MpegRecorder::kAudRateL1
40 {
41  32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
42 };
43 
44 const std::array<const int,14> MpegRecorder::kAudRateL2
45 {
46  32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
47 };
48 
49 const std::array<const int,14> MpegRecorder::kAudRateL3
50 {
51  32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
52 };
53 
54 const std::array<const std::string,15> MpegRecorder::kStreamType
55 {
56  "MPEG-2 PS", "MPEG-2 TS", "MPEG-1 VCD", "PES AV",
57  "", "PES V", "", "PES A",
58  "", "", "DVD", "VCD",
59  "SVCD", "DVD-Special 1", "DVD-Special 2"
60 };
61 
62 const std::array<const std::string,4> MpegRecorder::kAspectRatio
63 {
64  "Square", "4:3", "16:9", "2.21:1"
65 };
66 
68 {
69  StopRecording();
70 
71  if (m_chanfd >= 0)
72  {
73  close(m_chanfd);
74  m_chanfd = -1;
75  }
76  if (m_readfd >= 0)
77  {
78  close(m_readfd);
79  m_readfd = -1;
80  }
81 
83  {
86 
87  delete m_deviceReadBuffer;
88  m_deviceReadBuffer = nullptr;
89  }
90 
91 }
92 
93 static int find_index(const std::array<const int,14> &audio_rate, int value)
94 {
95  for (uint i = 0; i < audio_rate.size(); i++)
96  {
97  if (audio_rate[i] == value)
98  return i;
99  }
100 
101  return -1;
102 }
103 
104 void MpegRecorder::SetOption(const QString &opt, int value)
105 {
106  if (opt == "width")
107  m_width = value;
108  else if (opt == "height")
109  m_height = value;
110  else if (opt == "mpeg2bitrate")
111  m_bitrate = value;
112  else if (opt == "mpeg2maxbitrate")
113  m_maxBitrate = value;
114  else if (opt == "samplerate")
115  m_audSampleRate = value;
116  else if (opt == "mpeg2audbitratel1")
117  {
118  int index = find_index(kAudRateL1, value);
119  if (index >= 0)
120  m_audBitrateL1 = index + 1;
121  else
122  {
123  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L1): " +
124  QString("%1 is invalid").arg(value));
125  }
126  }
127  else if (opt == "mpeg2audbitratel2")
128  {
129  int index = find_index(kAudRateL2, value);
130  if (index >= 0)
131  m_audBitrateL2 = index + 1;
132  else
133  {
134  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
135  QString("%1 is invalid").arg(value));
136  }
137  }
138  else if (opt == "mpeg2audbitratel3")
139  {
140  int index = find_index(kAudRateL3, value);
141  if (index >= 0)
142  m_audBitrateL3 = index + 1;
143  else
144  {
145  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
146  QString("%1 is invalid").arg(value));
147  }
148  }
149  else if (opt == "mpeg2audvolume")
150  {
151  m_audVolume = value;
152  }
153  else if (opt.endsWith("_mpeg4avgbitrate"))
154  {
155  if (opt.startsWith("low"))
156  m_lowMpeg4AvgBitrate = value;
157  else if (opt.startsWith("medium"))
158  m_mediumMpeg4AvgBitrate = value;
159  else if (opt.startsWith("high"))
160  m_highMpeg4AvgBitrate = value;
161  else
162  V4LRecorder::SetOption(opt, value);
163  }
164  else if (opt.endsWith("_mpeg4peakbitrate"))
165  {
166  if (opt.startsWith("low"))
167  m_lowMpeg4PeakBitrate = value;
168  else if (opt.startsWith("medium"))
169  m_mediumMpeg4PeakBitrate = value;
170  else if (opt.startsWith("high"))
171  m_highMpeg4PeakBitrate = value;
172  else
173  V4LRecorder::SetOption(opt, value);
174  }
175  else
176  {
177  V4LRecorder::SetOption(opt, value);
178  }
179 }
180 
181 void MpegRecorder::SetOption(const QString &opt, const QString &value)
182 {
183  std::string value_ss = value.toStdString();
184  if (opt == "mpeg2streamtype")
185  {
186  bool found = false;
187  for (size_t i = 0; i < kStreamType.size(); i++)
188  {
189  if (kStreamType[i] == value_ss)
190  {
191  if (kStreamType[i] == "MPEG-2 TS")
192  {
194  }
195  else if (kStreamType[i] == "MPEG-2 PS")
196  {
198  }
199  else
200  {
201  // TODO Expand AVContainer to include other types in
202  // streamType
204  }
205  m_streamType = i;
206  found = true;
207  break;
208  }
209  }
210 
211  if (!found)
212  {
213  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 stream type: " +
214  QString("%1 is invalid").arg(value));
215  }
216  }
217  else if (opt == "mpeg2language")
218  {
219  bool ok = false;
220  m_language = value.toInt(&ok); // on failure language will be 0
221  if (!ok)
222  {
223  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 language (stereo) flag " +
224  QString("'%1' is invalid").arg(value));
225  }
226  }
227  else if (opt == "mpeg2aspectratio")
228  {
229  bool found = false;
230  for (size_t i = 0; i < kAspectRatio.size(); i++)
231  {
232  if (kAspectRatio[i] == value_ss)
233  {
234  m_aspectRatio = i + 1;
235  found = true;
236  break;
237  }
238  }
239 
240  if (!found)
241  {
242  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 Aspect-ratio: " +
243  QString("%1 is invalid").arg(value));
244  }
245  }
246  else if (opt == "mpeg2audtype")
247  {
248  if (value == "Layer I")
249  m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_1 + 1;
250  else if (value == "Layer II")
251  m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_2 + 1;
252  else if (value == "Layer III")
253  m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_3 + 1;
254  else
255  {
256  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 audio layer: " +
257  QString("%1 is invalid").arg(value));
258  }
259  }
260  else if (opt == "audiocodec")
261  {
262  if (value == "AAC Hardware Encoder")
263  m_audType = V4L2_MPEG_AUDIO_ENCODING_AAC + 1;
264  else if (value == "AC3 Hardware Encoder")
265  m_audType = V4L2_MPEG_AUDIO_ENCODING_AC3 + 1;
266  }
267  else
268  {
269  V4LRecorder::SetOption(opt, value);
270  }
271 }
272 
274  const QString &videodev,
275  [[maybe_unused]] const QString &audiodev,
276  [[maybe_unused]] const QString &vbidev)
277 {
278  if (videodev.startsWith("file:", Qt::CaseInsensitive))
279  {
280  m_deviceIsMpegFile = true;
281  m_bufferSize = 64000;
282  QString newVideoDev = videodev;
283  if (newVideoDev.startsWith("file:", Qt::CaseInsensitive))
284  newVideoDev = newVideoDev.remove(0,5);
285  SetOption("videodevice", newVideoDev);
286  }
287  else
288  {
289  SetOption("videodevice", videodev);
290  }
291  SetOption("vbidevice", vbidev);
292  SetOption("audiodevice", audiodev);
293 
294  SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
295  SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
296 
297  SetIntOption(profile, "mpeg2bitrate");
298  SetIntOption(profile, "mpeg2maxbitrate");
299  SetStrOption(profile, "mpeg2streamtype");
300  SetStrOption(profile, "mpeg2aspectratio");
301  SetStrOption(profile, "mpeg2language");
302 
303  SetIntOption(profile, "samplerate");
304  SetStrOption(profile, "mpeg2audtype");
305  SetIntOption(profile, "mpeg2audbitratel1");
306  SetIntOption(profile, "mpeg2audbitratel2");
307  SetIntOption(profile, "mpeg2audbitratel3");
308  SetIntOption(profile, "mpeg2audvolume");
309 
310  SetIntOption(profile, "width");
311  SetIntOption(profile, "height");
312 
313  SetIntOption(profile, "low_mpeg4avgbitrate");
314  SetIntOption(profile, "low_mpeg4peakbitrate");
315  SetIntOption(profile, "medium_mpeg4avgbitrate");
316  SetIntOption(profile, "medium_mpeg4peakbitrate");
317  SetIntOption(profile, "high_mpeg4avgbitrate");
318  SetIntOption(profile, "high_mpeg4peakbitrate");
319 
320  SetStrOption(profile, "audiocodec");
321 }
322 
323 // same as the base class, it just doesn't complain if an option is missing
325 {
326  const StandardSetting *setting = profile->byName(name);
327  if (setting)
328  SetOption(name, setting->getValue().toInt());
329 }
330 
331 // same as the base class, it just doesn't complain if an option is missing
333 {
334  const StandardSetting *setting = profile->byName(name);
335  if (setting)
336  SetOption(name, setting->getValue());
337 }
338 
340 {
341  QByteArray vdevice = m_videodevice.toLatin1();
342  m_chanfd = m_readfd = open(vdevice.constData(), O_RDONLY);
343 
344  if (m_readfd < 0)
345  {
346  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Can't open MPEG File '%1'")
347  .arg(m_videodevice) + ENO);
348  m_error = LOC + QString("Can't open MPEG File '%1'")
349  .arg(m_videodevice) + ENO;
350  return false;
351  }
352  return true;
353 }
354 
356 {
357  // open implicitly starts encoding, so we need the lock..
358  QMutexLocker locker(&m_startStopEncodingLock);
359 
360  QByteArray vdevice = m_videodevice.toLatin1();
361  m_chanfd = open(vdevice.constData(), O_RDWR);
362  if (m_chanfd < 0)
363  {
364  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device. " + ENO);
365  m_error = LOC + "Can't open video device. " + ENO;
366  return false;
367  }
368 
369  m_bufferSize = 4096;
370 
371  bool supports_tuner = false;
372  bool supports_audio = false;
373  uint32_t capabilities = 0;
374  if (CardUtil::GetV4LInfo(m_chanfd, m_card, m_driver, m_version, capabilities))
375  {
376  m_supportsSlicedVbi = ((capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) != 0U);
377  supports_tuner = ((capabilities & V4L2_CAP_TUNER) != 0U);
378  supports_audio = ((capabilities & V4L2_CAP_AUDIO) != 0U);
380  if (m_driver == "hdpvr")
381  {
382  m_bufferSize = 1500 * TSPacket::kSize;
383  m_useIForKeyframe = false;
384  }
385  }
386 
387  if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE))
388  {
389  LOG(VB_GENERAL, LOG_ERR, LOC + "V4L version 1, unsupported");
390  m_error = LOC + "V4L version 1, unsupported";
391  close(m_chanfd);
392  m_chanfd = -1;
393  return false;
394  }
395 
397  {
398  close(m_chanfd);
399  m_chanfd = -1;
400  return false;
401  }
402 
403  if (supports_tuner)
404  SetLanguageMode(m_chanfd); // we don't care if this fails...
405 
406  if (supports_audio)
407  SetRecordingVolume(m_chanfd); // we don't care if this fails...
408 
410  {
411  close(m_chanfd);
412  m_chanfd = -1;
413  return false;
414  }
415 
416  SetVBIOptions(m_chanfd); // we don't care if this fails...
417 
418  m_readfd = open(vdevice.constData(), O_RDWR | O_NONBLOCK);
419 
420  if (m_readfd < 0)
421  {
422  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device." + ENO);
423  m_error = LOC + "Can't open video device." + ENO;
424  close(m_chanfd);
425  m_chanfd = -1;
426  return false;
427  }
428 
429  if (m_deviceReadBuffer)
430  {
433 
434  delete m_deviceReadBuffer;
435  m_deviceReadBuffer = nullptr;
436  }
437 
439 
440  if (!m_deviceReadBuffer)
441  {
442  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer");
443  m_error = "Failed to allocate DRB buffer";
444  close(m_chanfd);
445  m_chanfd = -1;
446  close(m_readfd);
447  m_readfd = -1;
448  return false;
449  }
450 
451  if (!m_deviceReadBuffer->Setup(vdevice.constData(), m_readfd))
452  {
453  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup DRB buffer");
454  m_error = "Failed to setup DRB buffer";
455  close(m_chanfd);
456  m_chanfd = -1;
457  close(m_readfd);
458  m_readfd = -1;
459  return false;
460  }
461 
462  LOG(VB_RECORD, LOG_INFO, LOC + "DRB ready");
463 
464  if (m_vbiFd >= 0)
465  m_vbiThread = new VBIThread(this);
466 
467  return true;
468 }
469 
470 
472 {
473  if (m_driver == "hdpvr")
474  return true;
475 
476  struct v4l2_format vfmt {};
477 
478  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
479 
480  if (ioctl(chanfd, VIDIOC_G_FMT, &vfmt) < 0)
481  {
482  LOG(VB_GENERAL, LOG_ERR, LOC + "Error getting format" + ENO);
483  m_error = LOC + "Error getting format" + ENO;
484  return false;
485  }
486 
487  vfmt.fmt.pix.width = m_width;
488  vfmt.fmt.pix.height = m_height;
489 
490  if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) < 0)
491  {
492  LOG(VB_GENERAL, LOG_ERR, LOC + "Error setting format" + ENO);
493  m_error = LOC + "Error setting format" + ENO;
494  return false;
495  }
496 
497  return true;
498 }
499 
502 {
503  struct v4l2_tuner vt {};
504  if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
505  {
506  LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to get audio mode" + ENO);
507  return false;
508  }
509 
510  switch (m_language)
511  {
512  case 0:
513  vt.audmode = V4L2_TUNER_MODE_LANG1;
514  break;
515  case 1:
516  vt.audmode = V4L2_TUNER_MODE_LANG2;
517  break;
518  case 2:
519  vt.audmode = V4L2_TUNER_MODE_LANG1_LANG2;
520  break;
521  default:
522  vt.audmode = V4L2_TUNER_MODE_LANG1;
523  }
524 
525  int audio_layer = GetFilteredAudioLayer();
526  bool success = true;
527  if ((2 == m_language) && (1 == audio_layer))
528  {
529  LOG(VB_GENERAL, LOG_WARNING,
530  "Dual audio mode incompatible with Layer I audio."
531  "\n\t\t\tFalling back to Main Language");
532  vt.audmode = V4L2_TUNER_MODE_LANG1;
533  success = false;
534  }
535 
536  if (ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
537  {
538  LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to set audio mode" + ENO);
539  success = false;
540  }
541 
542  return success;
543 }
544 
546 {
547  // Get volume min/max values
548  struct v4l2_queryctrl qctrl {};
549  qctrl.id = V4L2_CID_AUDIO_VOLUME;
550  if ((ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) < 0) ||
551  (qctrl.flags & V4L2_CTRL_FLAG_DISABLED))
552  {
553  LOG(VB_CHANNEL, LOG_WARNING,
554  LOC + "Audio volume control not supported.");
555  return false;
556  }
557 
558  // calculate volume in card units.
559  int range = qctrl.maximum - qctrl.minimum;
560  int value = (int) ((range * m_audVolume * 0.01F) + qctrl.minimum);
561  int ctrl_volume = std::clamp(value, qctrl.minimum, qctrl.maximum);
562 
563  // Set recording volume
564  struct v4l2_control ctrl {V4L2_CID_AUDIO_VOLUME, ctrl_volume};
565 
566  if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
567  {
568  LOG(VB_GENERAL, LOG_WARNING, LOC +
569  "Unable to set recording volume" + ENO + "\n\t\t\t" +
570  "If you are using an AverMedia M179 card this is normal.");
571  return false;
572  }
573 
574  return true;
575 }
576 
578 {
579  uint st = (uint) m_streamType;
580 
581  if (m_driver == "ivtv")
582  {
583  switch (st)
584  {
585  case 2: st = 2; break;
586  case 10:
587  case 13:
588  case 14: st = 10; break;
589  case 11: st = 11; break;
590  case 12: st = 12; break;
591  default: st = 0; break;
592  }
593  }
594 
595  if (st != (uint) m_streamType)
596  {
597  LOG(VB_GENERAL, LOG_WARNING, LOC +
598  QString("Stream type '%1'\n\t\t\t"
599  "is not supported by %2 driver, using '%3' instead.")
600  .arg(QString::fromStdString(kStreamType[m_streamType]),
601  m_driver,
602  QString::fromStdString(kStreamType[st])));
603  }
604 
605  return st;
606 }
607 
609 {
610  uint sr = (uint) m_audSampleRate;
611 
612  sr = (m_driver == "ivtv") ? 48000 : sr; // only 48kHz works properly.
613 
614  if (sr != (uint) m_audSampleRate)
615  {
616  LOG(VB_GENERAL, LOG_WARNING, LOC +
617  QString("Audio sample rate %1 Hz\n\t\t\t"
618  "is not supported by %2 driver, using %3 Hz instead.")
619  .arg(m_audSampleRate).arg(m_driver).arg(sr));
620  }
621 
622  switch (sr)
623  {
624  case 32000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
625  case 44100: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
626  case 48000:
627  default: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
628  }
629 }
630 
632 {
633  uint layer = (uint) m_audType;
634 
635  layer = std::clamp(layer, 1U, 3U);
636 
637  layer = (m_driver == "ivtv") ? 2 : layer;
638 
639  if (layer != (uint) m_audType)
640  {
641  LOG(VB_GENERAL, LOG_WARNING, LOC +
642  QString("MPEG layer %1 does not work properly\n\t\t\t"
643  "with %2 driver. Using MPEG layer %3 audio instead.")
644  .arg(m_audType).arg(m_driver).arg(layer));
645  }
646 
647  return layer;
648 }
649 
651 {
652  if (2 == audio_layer)
653  return std::max(m_audBitrateL2, 10);
654  if (3 == audio_layer)
655  return m_audBitrateL3;
656  return std::max(m_audBitrateL1, 6);
657 }
658 
659 static int streamtype_ivtv_to_v4l2(int st)
660 {
661  switch (st)
662  {
663  case 0: return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
664  case 1: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
665  case 2: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD;
666  case 3: /* PES A/V */
667  case 5: /* PES V */
668  case 7: /* PES A */
669  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
670  case 10: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
671  case 11: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD; /* VCD */
672  case 12: return V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD;
673  case 13: /* DVD-Special 1 */
674  case 14: /* DVD-Special 2 */
675  return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
676  default: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
677  }
678 }
679 
680 static void add_ext_ctrl(std::vector<struct v4l2_ext_control> &ctrl_list,
681  uint32_t id, int32_t value)
682 {
683  struct v4l2_ext_control tmp_ctrl {};
684  tmp_ctrl.id = id;
685  tmp_ctrl.value = value;
686  ctrl_list.push_back(tmp_ctrl);
687 }
688 
689 static void set_ctrls(int fd, std::vector<struct v4l2_ext_control> &ext_ctrls)
690 {
691  static QMutex s_controlDescriptionLock;
692  static QMap<uint32_t,QString> s_controlDescription;
693 
694  s_controlDescriptionLock.lock();
695  if (s_controlDescription.isEmpty())
696  {
697  s_controlDescription[V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ] =
698  "Audio Sampling Frequency";
699  s_controlDescription[V4L2_CID_MPEG_VIDEO_ASPECT] =
700  "Video Aspect ratio";
701  s_controlDescription[V4L2_CID_MPEG_AUDIO_ENCODING] =
702  "Audio Encoding";
703  s_controlDescription[V4L2_CID_MPEG_AUDIO_L2_BITRATE] =
704  "Audio L2 Bitrate";
705  s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE_PEAK] =
706  "Video Peak Bitrate";
707  s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE] =
708  "Video Average Bitrate";
709  s_controlDescription[V4L2_CID_MPEG_STREAM_TYPE] =
710  "MPEG Stream type";
711  s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE_MODE] =
712  "MPEG Bitrate mode";
713  }
714  s_controlDescriptionLock.unlock();
715 
716  for (auto & ext_ctrl : ext_ctrls)
717  {
718  struct v4l2_ext_controls ctrls {};
719 
720  int value = ext_ctrl.value;
721 
722  ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
723  ctrls.count = 1;
724  ctrls.controls = &ext_ctrl;
725 
726  if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
727  {
728  QMutexLocker locker(&s_controlDescriptionLock);
729  LOG(VB_GENERAL, LOG_ERR, QString("mpegrecorder.cpp:set_ctrls(): ") +
730  QString("Could not set %1 to %2")
731  .arg(s_controlDescription[ext_ctrl.id]).arg(value) +
732  ENO);
733  }
734  }
735 }
736 
738 {
739  std::vector<struct v4l2_ext_control> ext_ctrls;
740 
741  // Set controls
742  if (m_driver != "hdpvr")
743  {
744  if (!m_driver.startsWith("saa7164"))
745  {
746  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
748 
749  uint audio_layer = GetFilteredAudioLayer();
750  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_ENCODING,
751  audio_layer - 1);
752 
753  uint audbitrate = GetFilteredAudioBitRate(audio_layer);
754  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_L2_BITRATE,
755  audbitrate - 1);
756  }
757 
758  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_ASPECT,
759  m_aspectRatio - 1);
760 
761  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_STREAM_TYPE,
763 
764  }
765  else
766  {
769  }
770  m_maxBitrate = std::max(m_maxBitrate, m_bitrate);
771 
772  if (m_driver == "hdpvr" || m_driver.startsWith("saa7164"))
773  {
774  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
775  (m_maxBitrate == m_bitrate) ?
776  V4L2_MPEG_VIDEO_BITRATE_MODE_CBR :
777  V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
778  }
779 
780  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE,
781  m_bitrate * 1000);
782 
783  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
784  m_maxBitrate * 1000);
785 
786  set_ctrls(chanfd, ext_ctrls);
787 
788  bool ok = false;
789  int audioinput = m_audioDeviceName.toUInt(&ok);
790  if (ok)
791  {
792  struct v4l2_audio ain {};
793  ain.index = audioinput;
794  if (ioctl(chanfd, VIDIOC_ENUMAUDIO, &ain) < 0)
795  {
796  LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to get audio input.");
797  }
798  else
799  {
800  ain.index = audioinput;
801  if (ioctl(chanfd, VIDIOC_S_AUDIO, &ain) < 0)
802  {
803  LOG(VB_GENERAL, LOG_WARNING,
804  LOC + "Unable to set audio input.");
805  }
806  }
807  }
808 
809  // query supported audio codecs if spdif is not used
810  if (m_driver == "hdpvr" && audioinput != 2)
811  {
812  struct v4l2_queryctrl qctrl {};
813  qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
814 
815  if (!ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl))
816  {
817  uint audio_enc = std::clamp(m_audType-1, qctrl.minimum, qctrl.maximum);
818  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_ENCODING, audio_enc);
819  }
820  else
821  {
822  LOG(VB_GENERAL, LOG_WARNING, LOC +
823  "Unable to get supported audio codecs." + ENO);
824  }
825  }
826 
827  return true;
828 }
829 
831 {
832  if (VBIMode::None == m_vbiMode)
833  return true;
834 
835  if (m_driver == "hdpvr")
836  return true;
837 
838 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
840  {
841  int fd = 0;
842 
843  if (OpenVBIDevice() >= 0)
844  fd = m_vbiFd;
845  else
846  fd = chanfd;
847 
848  struct v4l2_format vbifmt {};
849  vbifmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
850  vbifmt.fmt.sliced.service_set |= (VBIMode::PAL_TT == m_vbiMode) ?
851  V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
852 
853  if (ioctl(fd, VIDIOC_S_FMT, &vbifmt) < 0)
854  {
855  if (m_vbiFd >= 0)
856  {
857  fd = chanfd; // Retry with video device instead
858  if (ioctl(fd, VIDIOC_S_FMT, &vbifmt) < 0)
859  {
860  LOG(VB_GENERAL, LOG_WARNING, LOC +
861  "Unable to enable VBI embedding (/dev/vbiX)" + ENO);
862  return false;
863  }
864  }
865  else
866  {
867  LOG(VB_GENERAL, LOG_WARNING, LOC +
868  "Unable to enable VBI embedding (/dev/videoX)" + ENO);
869  return false;
870  }
871  }
872 
873  if (ioctl(fd, VIDIOC_G_FMT, &vbifmt) >= 0)
874  {
875  LOG(VB_RECORD, LOG_INFO,
876  LOC + QString("VBI service: %1, io size: %2")
877  .arg(vbifmt.fmt.sliced.service_set)
878  .arg(vbifmt.fmt.sliced.io_size));
879 
880  struct v4l2_ext_control vbi_ctrl {};
881  vbi_ctrl.id = V4L2_CID_MPEG_STREAM_VBI_FMT;
882  vbi_ctrl.value = V4L2_MPEG_STREAM_VBI_FMT_IVTV;
883 
884  struct v4l2_ext_controls ctrls {};
885  ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
886  ctrls.count = 1;
887  ctrls.controls = &vbi_ctrl;
888 
889  if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
890  {
891  LOG(VB_GENERAL, LOG_WARNING, LOC +
892  "Unable to set VBI embedding format" + ENO);
893  }
894  else
895  {
896  return true;
897  }
898  }
899  }
900 #endif // V4L2_CAP_SLICED_VBI_CAPTURE
901 
902  return OpenVBIDevice() >= 0;
903 }
904 
906 {
907  ResetForNewFile();
909 }
910 
912 {
913  if (!Open())
914  {
915  if (m_error.isEmpty())
916  m_error = "Failed to open V4L device";
917  return;
918  }
919 
920  bool has_select = true;
921 
922 #if defined(__FreeBSD__)
923  // HACK. FreeBSD PVR150/500 driver doesn't currently support select()
924  has_select = false;
925 #endif
926 
927  if (m_driver == "hdpvr")
928  {
929  int progNum = 1;
930  auto *sd = new MPEGStreamData(progNum,
931  m_tvrec ? m_tvrec->GetInputId() : -1,
932  true);
933  sd->SetRecordingType(m_recordingType);
934  SetStreamData(sd);
935 
938 
939  // Make sure the first things in the file are a PAT & PMT
943  }
944 
945  {
946  QMutexLocker locker(&m_pauseLock);
947  m_requestRecording = true;
948  m_requestHelper = true;
949  m_recording = true;
950  m_recordingWait.wakeAll();
951  }
952 
953  auto *buffer = new unsigned char[m_bufferSize + 1];
954  int len = 0;
955  int remainder = 0;
956 
957  bool good_data = false;
958  bool gap = false;
959  QDateTime gap_start;
960 
961  MythTimer elapsedTimer;
962  float elapsed = NAN;
963  long long bytesRead = 0;
964 
965  bool ok { false };
966  // Bytes per second, but env var is BITS PER SECOND
967  int dummyBPS = qEnvironmentVariableIntValue("DUMMYBPS", &ok) / 8;
968  if (ok)
969  {
970  LOG(VB_GENERAL, LOG_INFO,
971  LOC + QString("Throttling dummy recorder to %1 bits per second")
972  .arg(dummyBPS * 8));
973  }
974 
975  struct timeval tv {};
976  fd_set rdset;
977 
978  if (m_deviceIsMpegFile)
979  elapsedTimer.start();
980  else if (m_deviceReadBuffer)
981  {
982  LOG(VB_RECORD, LOG_INFO, LOC + "Initial startup of recorder");
983  StartEncoding();
984  }
985 
986  QByteArray vdevice = m_videodevice.toLatin1();
987  while (IsRecordingRequested() && !IsErrored())
988  {
989  if (PauseAndWait(100ms))
990  continue;
991 
992  if (m_deviceIsMpegFile)
993  {
994  if (dummyBPS && bytesRead)
995  {
996  elapsed = (elapsedTimer.elapsed().count() / 1000.0) + 1;
997  while ((bytesRead / elapsed) > dummyBPS)
998  {
999  std::this_thread::sleep_for(50ms);
1000  elapsed = (elapsedTimer.elapsed().count() / 1000.0) + 1;
1001  }
1002  }
1003  else if (GetFramesWritten())
1004  {
1005  elapsed = (elapsedTimer.elapsed().count() / 1000.0) + 1;
1006  while ((GetFramesWritten() / elapsed) > 30)
1007  {
1008  std::this_thread::sleep_for(50ms);
1009  elapsed = (elapsedTimer.elapsed().count() / 1000.0) + 1;
1010  }
1011  }
1012  }
1013 
1014  if (m_deviceReadBuffer)
1015  {
1016  len = m_deviceReadBuffer->Read
1017  (&(buffer[remainder]), m_bufferSize - remainder);
1018 
1019  // Check for DRB errors
1021  {
1022  LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected");
1023 
1024  if (good_data)
1025  {
1026  if (gap)
1027  {
1028  /* Already processing a gap, which means
1029  * restarting the encoding didn't work! */
1030  SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
1031  }
1032  else
1033  {
1034  gap = true;
1035  }
1036  }
1037 
1038  if (!RestartEncoding())
1039  SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
1040  }
1041  else if (m_deviceReadBuffer->IsEOF() &&
1043  {
1044  LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected");
1045  m_error = "Device EOF detected";
1046  }
1047  else
1048  {
1049  // If we have seen good data, but now have a gap, note it
1050  if (good_data)
1051  {
1052  if (gap)
1053  {
1054  QMutexLocker locker(&m_statisticsLock);
1055  QDateTime gap_end(MythDate::current());
1056 
1057  m_recordingGaps.push_back(RecordingGap
1058  (gap_start, gap_end));
1059  LOG(VB_RECORD, LOG_DEBUG,
1060  LOC + QString("Inserted gap %1 dur %2")
1061  .arg(m_recordingGaps.back().toString())
1062  .arg(gap_start.secsTo(gap_end)));
1063  gap = false;
1064  }
1065  else
1066  {
1067  gap_start = MythDate::current();
1068  }
1069  }
1070  else
1071  {
1072  good_data = true;
1073  }
1074  }
1075  }
1076  else if (m_readfd < 0)
1077  {
1078  continue;
1079  }
1080  else
1081  {
1082  if (has_select)
1083  {
1084  tv.tv_sec = 5;
1085  tv.tv_usec = 0;
1086  FD_ZERO(&rdset); // NOLINT(readability-isolate-declaration)
1087  FD_SET(m_readfd, &rdset);
1088 
1089  switch (select(m_readfd + 1, &rdset, nullptr, nullptr, &tv))
1090  {
1091  case -1:
1092  if (errno == EINTR)
1093  continue;
1094 
1095  LOG(VB_GENERAL, LOG_ERR, LOC + "Select error" + ENO);
1096  continue;
1097 
1098  case 0:
1099  LOG(VB_GENERAL, LOG_ERR, LOC + "select timeout - "
1100  "driver has stopped responding");
1101 
1102  if (close(m_readfd) != 0)
1103  {
1104  LOG(VB_GENERAL, LOG_ERR, LOC + "Close error" + ENO);
1105  }
1106 
1107  // Force card to be reopened on next iteration..
1108  m_readfd = -1;
1109  continue;
1110 
1111  default:
1112  break;
1113  }
1114  }
1115 
1116  len = read(m_readfd, &(buffer[remainder]), m_bufferSize - remainder);
1117 
1118  if (len < 0 && !has_select)
1119  {
1120  QMutexLocker locker(&m_pauseLock);
1122  m_unpauseWait.wait(&m_pauseLock, 25);
1123  continue;
1124  }
1125 
1126  if ((len == 0) && (m_deviceIsMpegFile))
1127  {
1128  close(m_readfd);
1129  m_readfd = open(vdevice.constData(), O_RDONLY);
1130 
1131  if (m_readfd >= 0)
1132  {
1133  len = read(m_readfd,
1134  &(buffer[remainder]), m_bufferSize - remainder);
1135  }
1136 
1137  if (len <= 0)
1138  {
1139  m_error = "Failed to read from video file";
1140  continue;
1141  }
1142  }
1143  else if (len < 0 && errno != EAGAIN)
1144  {
1145  LOG(VB_GENERAL, LOG_ERR, LOC + QString("error reading from: %1")
1146  .arg(m_videodevice) + ENO);
1147  continue;
1148  }
1149  }
1150 
1151  if (len > 0)
1152  {
1153  bytesRead += len;
1154  len += remainder;
1155 
1156  if (m_driver == "hdpvr")
1157  {
1158  remainder = m_streamData->ProcessData(buffer, len);
1159  int start_remain = len - remainder;
1160  if (remainder && (start_remain >= remainder))
1161  memcpy(buffer, buffer+start_remain, remainder);
1162  else if (remainder)
1163  memmove(buffer, buffer+start_remain, remainder);
1164  }
1165  else
1166  {
1167  FindPSKeyFrames(buffer, len);
1168  }
1169  }
1170  }
1171 
1172  LOG(VB_RECORD, LOG_INFO, LOC + "run finishing up");
1173 
1174  StopEncoding();
1175 
1176  {
1177  QMutexLocker locker(&m_pauseLock);
1178  m_requestHelper = false;
1179  }
1180 
1181  if (m_vbiThread)
1182  {
1183  m_vbiThread->wait();
1184  delete m_vbiThread;
1185  m_vbiThread = nullptr;
1186  CloseVBIDevice();
1187  }
1188 
1189  FinishRecording();
1190 
1191  delete[] buffer;
1192 
1193  if (m_driver == "hdpvr")
1194  {
1197  SetStreamData(nullptr);
1198  }
1199 
1200  QMutexLocker locker(&m_pauseLock);
1201  m_requestRecording = false;
1202  m_recording = false;
1203  m_recordingWait.wakeAll();
1204 }
1205 
1206 bool MpegRecorder::ProcessTSPacket(const TSPacket &tspacket_real)
1207 {
1208  const uint pid = tspacket_real.PID();
1209 
1210  TSPacket *tspacket_fake = nullptr;
1211  if ((m_driver == "hdpvr") && (pid == 0x1001)) // PCRPID for HD-PVR
1212  {
1213  tspacket_fake = tspacket_real.CreateClone();
1214  uint cc = (m_continuityCounter[pid] == 0xFF) ?
1215  0 : (m_continuityCounter[pid] + 1) & 0xf;
1216  tspacket_fake->SetContinuityCounter(cc);
1217  }
1218 
1219  const TSPacket &tspacket = (tspacket_fake)
1220  ? *tspacket_fake : tspacket_real;
1221 
1222  bool ret = DTVRecorder::ProcessTSPacket(tspacket);
1223 
1224  delete tspacket_fake;
1225 
1226  return ret;
1227 }
1228 
1230 {
1231  LOG(VB_RECORD, LOG_INFO, LOC + "Reset(void)");
1232  ResetForNewFile();
1233 
1234  if (m_h2645Parser != nullptr)
1235  m_h2645Parser->Reset();
1236 
1237  m_startCode = 0xffffffff;
1238 
1239  if (m_curRecording)
1240  {
1242  }
1243  if (m_streamData)
1245 }
1246 
1248 {
1249  QMutexLocker locker(&m_pauseLock);
1251  m_paused = false;
1252  m_requestPause = true;
1253 }
1254 
1255 bool MpegRecorder::PauseAndWait(std::chrono::milliseconds timeout)
1256 {
1257  QMutexLocker locker(&m_pauseLock);
1258  if (m_requestPause)
1259  {
1260  if (!IsPaused(true))
1261  {
1262  LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait pause");
1263 
1264  StopEncoding();
1265 
1266  m_paused = true;
1267  m_pauseWait.wakeAll();
1268 
1269  if (m_tvrec)
1271  }
1272 
1273  m_unpauseWait.wait(&m_pauseLock, timeout.count());
1274  }
1275 
1276  if (!m_requestPause && IsPaused(true))
1277  {
1278  LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait unpause");
1279 
1280  if (m_driver == "hdpvr")
1281  {
1282  // HD-PVR will sometimes reset to defaults
1284  }
1285 
1286  StartEncoding();
1287 
1288  if (m_streamData)
1290 
1291  m_paused = false;
1292  }
1293 
1294  return IsPaused(true);
1295 }
1296 
1298 {
1299  LOG(VB_RECORD, LOG_INFO, LOC + "RestartEncoding");
1300 
1301  QMutexLocker locker(&m_startStopEncodingLock);
1302 
1303  StopEncoding();
1304 
1305  // Make sure the next things in the file are a PAT & PMT
1306  if (m_streamData &&
1309  {
1310  m_payloadBuffer.clear(); // No reason to keep part of a frame
1313  }
1314 
1315  if (m_driver == "hdpvr") // HD-PVR will sometimes reset to defaults
1317 
1318  return StartEncoding();
1319 }
1320 
1322 {
1323  QMutexLocker locker(&m_startStopEncodingLock);
1324 
1325  LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding");
1326 
1327  if (m_readfd < 0)
1328  {
1329  m_readfd = open(m_videodevice.toLatin1().constData(), O_RDWR | O_NONBLOCK);
1330  if (m_readfd < 0)
1331  {
1332  LOG(VB_GENERAL, LOG_ERR, LOC +
1333  "StartEncoding: Can't open video device." + ENO);
1334  m_error = "Failed to start recording";
1335  return false;
1336  }
1337  }
1338 
1339  if (m_h2645Parser != nullptr)
1340  m_h2645Parser->Reset();
1341 
1342  bool good_res = true;
1343  if (m_driver == "hdpvr")
1344  {
1345  m_waitForKeyframeOption = true;
1346  m_seenSps = false;
1347  good_res = HandleResolutionChanges();
1348  }
1349 
1350  // (at least) with the 3.10 kernel, the V4L2_ENC_CMD_START does
1351  // not reliably start the data flow from a HD-PVR. A read() seems
1352  // to work, though.
1353 
1354  int idx = 1;
1355  for ( ; idx < 50; ++idx)
1356  {
1357  uint8_t dummy = 0;
1358  int len = read(m_readfd, &dummy, 0);
1359  if (len == 0)
1360  break;
1361  if (idx == 20)
1362  {
1363  LOG(VB_GENERAL, LOG_ERR, LOC +
1364  "StartEncoding: read failing, re-opening device: " + ENO);
1365  close(m_readfd);
1366  std::this_thread::sleep_for(2ms);
1367  m_readfd = open(m_videodevice.toLatin1().constData(),
1368  O_RDWR | O_NONBLOCK);
1369  if (m_readfd < 0)
1370  {
1371  LOG(VB_GENERAL, LOG_ERR, LOC +
1372  "StartEncoding: Can't open video device." + ENO);
1373  m_error = "Failed to start recording";
1374  return false;
1375  }
1376  }
1377  else
1378  {
1379  LOG(VB_GENERAL, LOG_ERR, LOC +
1380  QString("StartEncoding: read failed, retry in %1 msec:")
1381  .arg(100 * idx) + ENO);
1382  std::this_thread::sleep_for(idx * 100us);
1383  }
1384  }
1385  if (idx == 50)
1386  {
1387  LOG(VB_GENERAL, LOG_ERR, LOC +
1388  "StartEncoding: read from video device failed." + ENO);
1389  m_error = "Failed to start recording";
1390  close(m_readfd);
1391  m_readfd = -1;
1392  return false;
1393  }
1394  if (idx > 0)
1395  {
1396  LOG(VB_RECORD, LOG_WARNING, LOC +
1397  QString("%1 read attempts required to start encoding").arg(idx));
1398  }
1399 
1400  if (!good_res) // Try again
1402 
1403  if (m_deviceReadBuffer)
1404  {
1405  m_deviceReadBuffer->Reset(m_videodevice.toLatin1().constData(), m_readfd);
1408  }
1409 
1410  return true;
1411 }
1412 
1414 {
1415  QMutexLocker locker(&m_startStopEncodingLock);
1416 
1417  LOG(VB_RECORD, LOG_INFO, LOC + "StopEncoding");
1418 
1419  if (m_readfd < 0)
1420  return;
1421 
1422  struct v4l2_encoder_cmd command {};
1423  command.cmd = V4L2_ENC_CMD_STOP;
1424  command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
1425 
1426  if (m_deviceReadBuffer)
1428 
1429  bool stopped = 0 == ioctl(m_readfd, VIDIOC_ENCODER_CMD, &command);
1430  if (stopped)
1431  {
1432  LOG(VB_RECORD, LOG_INFO, LOC + "Encoding stopped");
1433  }
1434  else if (errno != ENOTTY && errno != EINVAL)
1435  {
1436  // Some drivers do not support this ioctl at all. It is marked as
1437  // "experimental" in the V4L2 API spec. These drivers return EINVAL
1438  // in older kernels and ENOTTY in 3.1+
1439 
1440  LOG(VB_GENERAL, LOG_WARNING, LOC + "StopEncoding failed" + ENO);
1441  }
1442 
1444  {
1445  // allow last bits of data through..
1446  std::this_thread::sleep_for(20ms);
1448  }
1449 
1450  // close the fd so streamoff/streamon work in V4LChannel
1451  close(m_readfd);
1452  m_readfd = -1;
1453 }
1454 
1456 {
1459 }
1460 
1461 void MpegRecorder::SetBitrate(int bitrate, int maxbitrate,
1462  const QString & reason)
1463 {
1464  if (maxbitrate == bitrate)
1465  {
1466  LOG(VB_RECORD, LOG_INFO, LOC + QString("%1 bitrate %2 kbps CBR")
1467  .arg(reason).arg(bitrate));
1468  }
1469  else
1470  {
1471  LOG(VB_RECORD, LOG_INFO, LOC + QString("%1 bitrate %2/%3 kbps VBR")
1472  .arg(reason).arg(bitrate).arg(maxbitrate));
1473  }
1474 
1475  std::vector<struct v4l2_ext_control> ext_ctrls;
1476  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
1477  (maxbitrate == bitrate) ?
1478  V4L2_MPEG_VIDEO_BITRATE_MODE_CBR :
1479  V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
1480 
1481  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE,
1482  bitrate * 1000);
1483 
1484  add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
1485  maxbitrate * 1000);
1486 
1487  set_ctrls(m_readfd, ext_ctrls);
1488 }
1489 
1491 {
1492  LOG(VB_RECORD, LOG_INFO, LOC + "Checking Resolution");
1493  uint pix = 0;
1494  struct v4l2_format vfmt {};
1495  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1496 
1497  if (0 == ioctl(m_chanfd, VIDIOC_G_FMT, &vfmt))
1498  {
1499  LOG(VB_RECORD, LOG_INFO, LOC + QString("Got Resolution %1x%2")
1500  .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
1501  pix = vfmt.fmt.pix.width * vfmt.fmt.pix.height;
1502  }
1503 
1504  if (!pix)
1505  {
1506  LOG(VB_RECORD, LOG_INFO, LOC + "Giving up detecting resolution: " + ENO);
1507  return false; // nothing to do, we don't have a resolution yet
1508  }
1509 
1510  int old_max = m_maxBitrate;
1511  int old_avg = m_bitrate;
1512  if (pix <= 768*568)
1513  {
1516  }
1517  else if (pix >= 1920*1080)
1518  {
1521  }
1522  else
1523  {
1526  }
1527  m_maxBitrate = std::max(m_maxBitrate, m_bitrate);
1528 
1529  if ((old_max != m_maxBitrate) || (old_avg != m_bitrate))
1530  {
1531  if (old_max == old_avg)
1532  {
1533  LOG(VB_RECORD, LOG_INFO, LOC +
1534  QString("Old bitrate %1 CBR").arg(old_avg));
1535  }
1536  else
1537  {
1538  LOG(VB_RECORD, LOG_INFO,LOC +
1539  QString("Old bitrate %1/%2 VBR") .arg(old_avg).arg(old_max));
1540  }
1541 
1543  }
1544 
1545  return true;
1546 }
1547 
1549 {
1550  LOG(VB_VBI, LOG_INFO, LOC + QString("FormatCC(0x%1,0x%2)")
1551  .arg(code1,0,16).arg(code2,0,16));
1552  // TODO add to CC data vector
1553 
1554  // TODO find video frames in output and insert cc_data
1555  // as CEA-708 user_data packets containing CEA-608 captions
1557 }
MpegRecorder::Pause
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
Definition: mpegrecorder.cpp:1247
MpegRecorder::m_clearTimeOnPause
bool m_clearTimeOnPause
Definition: mpegrecorder.h:93
DTVRecorder::FindPSKeyFrames
void FindPSKeyFrames(const uint8_t *buffer, uint len) override
Definition: dtvrecorder.cpp:1123
DTVRecorder::HandleSingleProgramPMT
void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) override
Definition: dtvrecorder.cpp:1410
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
O_NONBLOCK
#define O_NONBLOCK
Definition: compat.h:328
MpegRecorder::m_version
uint32_t m_version
Definition: mpegrecorder.h:86
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:101
DeviceReadBuffer::Start
void Start(void)
Definition: DeviceReadBuffer.cpp:149
LOC
#define LOC
Definition: mpegrecorder.cpp:36
MpegRecorder::SetLanguageMode
bool SetLanguageMode(int chanfd)
Set audio language mode.
Definition: mpegrecorder.cpp:501
DeviceReadBuffer::Setup
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
Definition: DeviceReadBuffer.cpp:92
V4LRecorder::m_vbiThread
VBIThread * m_vbiThread
Definition: v4lrecorder.h:44
VBIMode::None
@ None
Definition: tv.h:12
MpegRecorder::Reset
void Reset(void) override
Reset the recorder to the startup state.
Definition: mpegrecorder.cpp:1229
MPEGStreamData::SetDesiredProgram
void SetDesiredProgram(int p)
Definition: mpegstreamdata.cpp:66
DTVRecorder::m_payloadBuffer
std::vector< unsigned char > m_payloadBuffer
Definition: dtvrecorder.h:167
MPEGStreamData::AddMPEGSPListener
void AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
Definition: mpegstreamdata.cpp:1722
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
RecorderBase::m_statisticsLock
QMutex m_statisticsLock
Definition: recorderbase.h:350
MpegRecorder::m_deviceIsMpegFile
bool m_deviceIsMpegFile
Definition: mpegrecorder.h:80
set_ctrls
static void set_ctrls(int fd, std::vector< struct v4l2_ext_control > &ext_ctrls)
Definition: mpegrecorder.cpp:689
DTVRecorder::ResetForNewFile
void ResetForNewFile(void) override
Definition: dtvrecorder.cpp:141
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
MpegRecorder::StartEncoding
bool StartEncoding(void)
Definition: mpegrecorder.cpp:1321
MpegRecorder::kAspectRatio
static const std::array< const std::string, 4 > kAspectRatio
Definition: mpegrecorder.h:125
V4LRecorder::m_requestHelper
volatile bool m_requestHelper
Definition: v4lrecorder.h:46
DTVRecorder::m_startCode
uint32_t m_startCode
Definition: dtvrecorder.h:136
V4LRecorder::OpenVBIDevice
int OpenVBIDevice(void)
Definition: v4lrecorder.cpp:66
MpegRecorder::SetIntOption
void SetIntOption(RecordingProfile *profile, const QString &name)
Definition: mpegrecorder.cpp:324
TSHeader::PID
unsigned int PID(void) const
Definition: tspacket.h:93
MpegRecorder::m_supportsSlicedVbi
bool m_supportsSlicedVbi
Definition: mpegrecorder.h:87
MpegRecorder::m_lowMpeg4PeakBitrate
unsigned int m_lowMpeg4PeakBitrate
Definition: mpegrecorder.h:111
MpegRecorder::PauseAndWait
bool PauseAndWait(std::chrono::milliseconds timeout=100ms) override
If m_requestPause is true, sets pause and blocks up to timeout milliseconds or until unpaused,...
Definition: mpegrecorder.cpp:1255
H2645Parser::Reset
virtual void Reset(void)
Definition: H2645Parser.cpp:92
MpegRecorder::GetFilteredAudioLayer
uint GetFilteredAudioLayer(void) const
Definition: mpegrecorder.cpp:631
DTVRecorder::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Definition: dtvrecorder.cpp:219
MpegRecorder::m_deviceReadBuffer
DeviceReadBuffer * m_deviceReadBuffer
Definition: mpegrecorder.h:129
RecorderBase::m_tvrec
TVRec * m_tvrec
Definition: recorderbase.h:290
DTVRecorder::IsErrored
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:46
DeviceReadBuffer::Read
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
Definition: DeviceReadBuffer.cpp:659
MpegRecorder::SetOption
void SetOption(const QString &opt, int value) override
handles the "wait_for_seqstart" option.
Definition: mpegrecorder.cpp:104
TSPacket::CreateClone
TSPacket * CreateClone(void) const
Definition: tspacket.h:224
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
V4LRecorder::VBIThread
friend class VBIThread
Definition: v4lrecorder.h:18
MpegRecorder::OpenMpegFileAsInput
bool OpenMpegFileAsInput(void)
Definition: mpegrecorder.cpp:339
MpegRecorder::m_driver
QString m_driver
Definition: mpegrecorder.h:85
DeviceReadBuffer
Buffers reads from device files.
Definition: DeviceReadBuffer.h:35
DTVRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: dtvrecorder.cpp:127
MpegRecorder::m_highMpeg4PeakBitrate
unsigned int m_highMpeg4PeakBitrate
Definition: mpegrecorder.h:115
DTVRecorder::m_recordingType
QString m_recordingType
Definition: dtvrecorder.h:131
MPEGStreamData::PMTSingleProgram
const ProgramMapTable * PMTSingleProgram(void) const
Definition: mpegstreamdata.h:266
MpegRecorder::m_highMpeg4AvgBitrate
unsigned int m_highMpeg4AvgBitrate
Definition: mpegrecorder.h:114
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
VBIMode::PAL_TT
@ PAL_TT
Definition: tv.h:13
MpegRecorder::OpenV4L2DeviceAsInput
bool OpenV4L2DeviceAsInput(void)
Definition: mpegrecorder.cpp:355
MpegRecorder::run
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
Definition: mpegrecorder.cpp:911
RecorderBase::m_pauseLock
QMutex m_pauseLock
Definition: recorderbase.h:313
close
#define close
Definition: compat.h:43
V4LRecorder::SetOption
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:54
MpegRecorder::m_height
int m_height
Definition: mpegrecorder.h:97
DTVRecorder::m_continuityCounter
std::array< uint8_t, 0x1fff+1 > m_continuityCounter
Definition: dtvrecorder.h:183
TSHeader::SetContinuityCounter
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:170
RecorderBase::m_requestPause
bool m_requestPause
Definition: recorderbase.h:314
RecorderBase::m_recordingWait
QWaitCondition m_recordingWait
Definition: recorderbase.h:322
RecorderBase::m_curRecording
RecordingInfo * m_curRecording
Definition: recorderbase.h:310
find_index
static int find_index(const std::array< const int, 14 > &audio_rate, int value)
Definition: mpegrecorder.cpp:93
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:3000
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:234
mythdate.h
MpegRecorder::SetV4L2DeviceOptions
bool SetV4L2DeviceOptions(int chanfd)
Definition: mpegrecorder.cpp:737
RecorderBase::m_paused
bool m_paused
Definition: recorderbase.h:315
MPEGStreamData::PATSingleProgram
const ProgramAssociationTable * PATSingleProgram(void) const
Definition: mpegstreamdata.h:264
DTVRecorder::HandleSingleProgramPAT
void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert) override
Definition: dtvrecorder.cpp:1390
programinfo.h
V4LRecorder::CloseVBIDevice
void CloseVBIDevice(void)
Definition: v4lrecorder.cpp:155
mythlogging.h
hardwareprofile.scan.profile
profile
Definition: scan.py:96
CardUtil::GetV4LInfo
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2354
formatMPEG2_TS
@ formatMPEG2_TS
Definition: recordingfile.h:16
formatMPEG2_PS
@ formatMPEG2_PS
Definition: recordingfile.h:17
RecorderBase::m_recordingGaps
RecordingGaps m_recordingGaps
Definition: recorderbase.h:357
MpegRecorder::HandleResolutionChanges
bool HandleResolutionChanges(void)
Definition: mpegrecorder.cpp:1490
TSPacket
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:207
MPEGStreamData::ProcessData
virtual int ProcessData(const unsigned char *buffer, int len)
Definition: mpegstreamdata.cpp:951
V4LRecorder::StopRecording
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:41
MpegRecorder::kStreamType
static const std::array< const std::string, 15 > kStreamType
Definition: mpegrecorder.h:124
RecStatus::Failing
@ Failing
Definition: recordingstatus.h:18
MpegRecorder::Open
bool Open(void)
Definition: mpegrecorder.cpp:905
DeviceReadBuffer::IsRunning
bool IsRunning(void) const
Definition: DeviceReadBuffer.cpp:297
MPEGStreamData
Encapsulates data about MPEG stream and emits events for each table.
Definition: mpegstreamdata.h:85
MpegRecorder::m_lowMpeg4AvgBitrate
unsigned int m_lowMpeg4AvgBitrate
Definition: mpegrecorder.h:110
MPEGStreamData::RemoveWritingListener
void RemoveWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1666
DTVRecorder::GetFramesWritten
long long GetFramesWritten(void) override
Returns number of frames written to disk.
Definition: dtvrecorder.h:49
MpegRecorder::m_bufferSize
int m_bufferSize
Definition: mpegrecorder.h:81
MpegRecorder::SetRecordingVolume
bool SetRecordingVolume(int chanfd)
Definition: mpegrecorder.cpp:545
RecorderBase::IsRecordingRequested
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.
Definition: recorderbase.cpp:254
DTVRecorder::m_h2645Parser
H2645Parser * m_h2645Parser
Definition: dtvrecorder.h:152
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:949
DTVRecorder::m_seenSps
bool m_seenSps
Definition: dtvrecorder.h:151
MpegRecorder::m_aspectRatio
int m_aspectRatio
Definition: mpegrecorder.h:101
MpegRecorder::m_language
unsigned int m_language
0 is Main Lang; 1 is SAP Lang; 2 is Dual
Definition: mpegrecorder.h:109
MpegRecorder::TeardownAll
void TeardownAll(void)
Definition: mpegrecorder.cpp:67
DeviceReadBuffer::Stop
void Stop(void)
Definition: DeviceReadBuffer.cpp:192
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
MpegRecorder::m_audBitrateL3
int m_audBitrateL3
Definition: mpegrecorder.h:106
DTVRecorder::ProcessTSPacket
bool ProcessTSPacket(const TSPacket &tspacket) override
Definition: dtvrecorder.cpp:1548
MpegRecorder::m_audVolume
int m_audVolume
Definition: mpegrecorder.h:107
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
RecorderBase::m_containerFormat
AVContainer m_containerFormat
Definition: recorderbase.h:294
MpegRecorder::SetVideoCaptureFormat
bool SetVideoCaptureFormat(int chanfd)
Definition: mpegrecorder.cpp:471
MpegRecorder::kAudRateL3
static const std::array< const int, 14 > kAudRateL3
Definition: mpegrecorder.h:123
MpegRecorder::GetFilteredStreamType
uint GetFilteredStreamType(void) const
Definition: mpegrecorder.cpp:577
MpegRecorder::GetFilteredAudioSampleRate
uint GetFilteredAudioSampleRate(void) const
Definition: mpegrecorder.cpp:608
mythmediabuffer.h
MARK_GOP_BYFRAME
@ MARK_GOP_BYFRAME
Definition: programtypes.h:63
RecorderBase::m_videodevice
QString m_videodevice
Definition: recorderbase.h:298
MpegRecorder::m_card
QString m_card
Definition: mpegrecorder.h:84
MpegRecorder::m_audBitrateL2
int m_audBitrateL2
Definition: mpegrecorder.h:105
MpegRecorder::SetOptionsFromProfile
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
Definition: mpegrecorder.cpp:273
MpegRecorder::FormatCC
void FormatCC(uint code1, uint code2) override
Definition: mpegrecorder.cpp:1548
RecorderBase::m_pauseWait
QWaitCondition m_pauseWait
Definition: recorderbase.h:316
MPEGStreamData::AddAVListener
void AddAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1680
MpegRecorder::InitStreamData
void InitStreamData(void) override
Definition: mpegrecorder.cpp:1455
MpegRecorder::m_mediumMpeg4AvgBitrate
unsigned int m_mediumMpeg4AvgBitrate
Definition: mpegrecorder.h:112
MpegRecorder::m_width
int m_width
Definition: mpegrecorder.h:96
DTVRecorder::m_waitForKeyframeOption
bool m_waitForKeyframeOption
Wait for the a GOP/SEQ-start before sending data.
Definition: dtvrecorder.h:155
MpegRecorder::StopEncoding
void StopEncoding(void)
Definition: mpegrecorder.cpp:1413
V4LRecorder::m_vbiMode
int m_vbiMode
Definition: v4lrecorder.h:39
MpegRecorder::m_maxBitrate
int m_maxBitrate
Definition: mpegrecorder.h:99
MpegRecorder::SetBitrate
void SetBitrate(int bitrate, int maxbitrate, const QString &reason)
Definition: mpegrecorder.cpp:1461
RecordingGap
Definition: recordingquality.h:14
MpegRecorder::GetFilteredAudioBitRate
uint GetFilteredAudioBitRate(uint audio_layer) const
Definition: mpegrecorder.cpp:650
RecorderBase::SetRecordingStatus
virtual void SetRecordingStatus(RecStatus::Type status, const QString &file, int line)
Definition: recorderbase.cpp:399
DTVRecorder::m_streamData
MPEGStreamData * m_streamData
Definition: dtvrecorder.h:163
mythcorecontext.h
MPEGStreamData::AddWritingListener
void AddWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1655
MPEGStreamData::DesiredProgram
int DesiredProgram(void) const
Definition: mpegstreamdata.h:260
cardutil.h
DTVRecorder::m_error
QString m_error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:161
DTVRecorder::m_useIForKeyframe
bool m_useIForKeyframe
Definition: dtvrecorder.h:215
ProgramInfo::ClearPositionMap
void ClearPositionMap(MarkTypes type) const
Definition: programinfo.cpp:3840
MpegRecorder::m_audType
int m_audType
Definition: mpegrecorder.h:102
MpegRecorder::m_startStopEncodingLock
QRecursiveMutex m_startStopEncodingLock
Definition: mpegrecorder.h:90
mpegrecorder.h
MpegRecorder::kAudRateL2
static const std::array< const int, 14 > kAudRateL2
Definition: mpegrecorder.h:122
MpegRecorder::m_audSampleRate
int m_audSampleRate
Definition: mpegrecorder.h:103
formatUnknown
@ formatUnknown
Definition: recordingfile.h:14
MpegRecorder::SetVBIOptions
bool SetVBIOptions(int chanfd)
Definition: mpegrecorder.cpp:830
RecorderBase::m_recording
bool m_recording
True while recording is actually being performed.
Definition: recorderbase.h:321
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
MpegRecorder::kAudRateL1
static const std::array< const int, 14 > kAudRateL1
Definition: mpegrecorder.h:121
tv_rec.h
DeviceReadBuffer::IsErrored
bool IsErrored(void) const
Definition: DeviceReadBuffer.cpp:285
MpegRecorder::SetStrOption
void SetStrOption(RecordingProfile *profile, const QString &name)
Definition: mpegrecorder.cpp:332
MpegRecorder::m_readfd
int m_readfd
Definition: mpegrecorder.h:119
StandardSetting
Definition: standardsettings.h:29
DeviceReadBuffer::IsEOF
bool IsEOF(void) const
Definition: DeviceReadBuffer.cpp:291
recordingprofile.h
DeviceReadBuffer::SetRequestPause
void SetRequestPause(bool request)
Definition: DeviceReadBuffer.cpp:206
add_ext_ctrl
static void add_ext_ctrl(std::vector< struct v4l2_ext_control > &ctrl_list, uint32_t id, int32_t value)
Definition: mpegrecorder.cpp:680
RecordingProfile
Definition: recordingprofile.h:41
MpegRecorder::m_audBitrateL1
int m_audBitrateL1
Definition: mpegrecorder.h:104
streamtype_ivtv_to_v4l2
static int streamtype_ivtv_to_v4l2(int st)
Definition: mpegrecorder.cpp:659
V4LRecorder::m_audioDeviceName
QString m_audioDeviceName
Definition: v4lrecorder.h:37
MpegRecorder::m_mediumMpeg4PeakBitrate
unsigned int m_mediumMpeg4PeakBitrate
Definition: mpegrecorder.h:113
RecorderBase::m_unpauseWait
QWaitCondition m_unpauseWait
Definition: recorderbase.h:317
MpegRecorder::RestartEncoding
bool RestartEncoding(void)
Definition: mpegrecorder.cpp:1297
MpegRecorder::m_streamType
int m_streamType
Definition: mpegrecorder.h:100
MPEGStreamData::RemoveAVListener
void RemoveAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1701
MpegRecorder::m_chanfd
int m_chanfd
Definition: mpegrecorder.h:118
MpegRecorder::m_bitrate
int m_bitrate
Definition: mpegrecorder.h:98
RecorderBase::IsPaused
virtual bool IsPaused(bool holding_lock=false) const
Returns true iff recorder is paused.
Definition: recorderbase.cpp:285
DeviceReadBuffer::Reset
void Reset(const QString &streamName, int streamfd)
Definition: DeviceReadBuffer.cpp:177
V4LRecorder::m_vbiFd
int m_vbiFd
Definition: v4lrecorder.h:45
uint
unsigned int uint
Definition: freesurround.h:24
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:904
RecorderBase::m_requestRecording
bool m_requestRecording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:319
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:261
MpegRecorder::ProcessTSPacket
bool ProcessTSPacket(const TSPacket &tspacket) override
Definition: mpegrecorder.cpp:1206