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