MythTV  master
v4l2encstreamhandler.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // POSIX headers
4 #include <fcntl.h>
5 #include <unistd.h>
6 #ifndef USING_MINGW
7 #include <poll.h>
8 //#include <sys/select.h>
9 #include <sys/ioctl.h>
10 #endif
11 
12 #include <chrono> // for milliseconds
13 #include <iostream>
14 #include <thread> // for sleep_for
15 
16 // Qt headers
17 #include <QFile>
18 #include <QString>
19 
20 // MythTV headers
21 #include "libmythbase/exitcodes.h"
22 
23 #include "cardutil.h"
24 #include "dtvsignalmonitor.h"
25 #include "mpeg/mpegstreamdata.h"
26 #include "mpeg/streamlisteners.h"
28 #include "recorders/v4lchannel.h"
29 
30 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
31  #define loadRelaxed load
32 #endif
33 
34 const std::array<const std::string,15> V4L2encStreamHandler::kStreamTypes
35 {
36  "MPEG-2 PS", "MPEG-2 TS", "MPEG-1 VCD", "PES AV",
37  "", "PES V", "", "PES A",
38  "", "", "DVD", "VCD",
39  "SVCD", "DVD-Special 1", "DVD-Special 2"
40 };
41 
42 const std::array<const int,14> V4L2encStreamHandler::kAudioRateL1
43 {
44  32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
45 };
46 
47 const std::array<const int,14> V4L2encStreamHandler::kAudioRateL2
48 {
49  32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
50 };
51 
52 const std::array<const int,14> V4L2encStreamHandler::kAudioRateL3
53 {
54  32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
55 };
56 
57 #define LOC QString("V4L2SH[%1](%2): ").arg(m_inputId).arg(m_device)
58 
59 QMap<QString,V4L2encStreamHandler*> V4L2encStreamHandler::s_handlers;
62 
64  int audioinput, int inputid)
65 {
66  QMutexLocker locker(&s_handlers_lock);
67 
68  const QString& devkey = devname;
69 
70  QMap<QString,V4L2encStreamHandler*>::iterator it = s_handlers.find(devkey);
71 
72  if (it == s_handlers.end())
73  {
74  auto *newhandler = new V4L2encStreamHandler(devname, audioinput, inputid);
75 
76  s_handlers[devkey] = newhandler;
77  s_handlers_refcnt[devkey] = 1;
78 
79  LOG(VB_RECORD, LOG_INFO,
80  QString("V4L2SH[%1]: Creating new stream handler for %2")
81  .arg(inputid).arg(devname));
82  }
83  else
84  {
85  s_handlers_refcnt[devkey]++;
86  uint rcount = s_handlers_refcnt[devkey];
87  LOG(VB_RECORD, LOG_INFO,
88  QString("V4L2SH[%1]: Using existing stream handler for %2")
89  .arg(inputid).arg(devkey) + QString(" (%1 in use)").arg(rcount));
90  }
91 
92  return s_handlers[devkey];
93 }
94 
96 {
97  QMutexLocker locker(&s_handlers_lock);
98 
99  QString devname = ref->m_device;
100 
101  QMap<QString,uint>::iterator rit = s_handlers_refcnt.find(devname);
102  if (rit == s_handlers_refcnt.end())
103  return;
104 
105  LOG(VB_RECORD, LOG_INFO, QString("V4L2SH[%1]: Return '%2' in use %3")
106  .arg(inputid).arg(devname).arg(*rit));
107 
108  if (*rit > 1)
109  {
110  ref = nullptr;
111  --(*rit);
112  return;
113  }
114 
115  QMap<QString, V4L2encStreamHandler*>::iterator it =
116  s_handlers.find(devname);
117  if ((it != s_handlers.end()) && (*it == ref))
118  {
119  LOG(VB_RECORD, LOG_INFO, QString("V4L2SH[%1]: Closing handler for %2")
120  .arg(inputid).arg(devname));
121  delete *it;
122  s_handlers.erase(it);
123  }
124  else
125  {
126  LOG(VB_GENERAL, LOG_ERR,
127  QString("V4L2SH[%1]: Error: Couldn't find handler for %2")
128  .arg(inputid).arg(devname));
129  }
130 
131  s_handlers_refcnt.erase(rit);
132  ref = nullptr;
133 }
134 
135 /*
136  V4L2encStreamHandler
137 */
138 bool V4L2encStreamHandler::Status(bool &failed, bool &failing)
139 {
140  failed = !IsRunning();
141  failing = m_failing;
142  return !failed && !failing;
143 }
144 
146  int audio_input, int inputid)
147  : StreamHandler(device, inputid)
148  , m_audioInput(audio_input)
149 {
150  setObjectName("V4L2encSH");
151 
152  if (!Open())
153  {
154  LOG(VB_GENERAL, LOG_ERR, LOC + QString("-- Failed to open %1: ")
155  .arg(m_device) + ENO);
156  m_bError = true;
157  return;
158  }
159  LOG(VB_RECORD, LOG_INFO, LOC + QString("'%1' open").arg(m_device));
160 }
161 
163 {
164  StopEncoding();
165  Close();
166 }
167 
169 {
170  RunProlog();
171 
172  LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin");
173 
174  if (!IsOpen())
175  {
176  LOG(VB_GENERAL, LOG_WARNING, LOC +
177  "Starting stream handler, but v4l2 is not open!");
178  if (!Open())
179  {
180  LOG(VB_GENERAL, LOG_ERR, LOC +
181  QString("run() -- Failed to open %1: ")
182  .arg(m_device) + ENO);
183  m_bError = true;
184  return;
185  }
186  }
187 
188 #if 0
189  // VBI
190  if (m_vbi_fd >= 0)
191  m_vbi_thread = new VBIThread(this);
192 #endif
193 
194  bool good_data = false;
195  bool gap = false;
196 
197  QByteArray buffer;
198  char* pkt_buf = new char[PACKET_SIZE + 1];
199 
200  SetRunning(true, true, false);
201 
202  while (m_runningDesired && !m_bError)
203  {
204  // Get V4L2 data
205  if (m_streamingCnt.loadRelaxed() == 0)
206  {
207  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for stream start.");
208  QMutexLocker locker(&m_startStopLock);
210  continue;
211  }
212 
213  // Check for errors
214 
215  if (!m_drb)
216  break;
217 
218  int len = m_drb->Read(reinterpret_cast<unsigned char *>(pkt_buf),
219  PACKET_SIZE);
220  if (m_drb->IsErrored())
221  {
222  LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- Device error detected");
223 
224  if (good_data)
225  {
226  if (gap)
227  {
228  /* Already processing a gap, which means
229  * restarting the encoding didn't work! */
230  m_failing = true;
231  }
232  else
233  gap = true;
234  }
235 
236  RestartEncoding();
237  }
238  else if (m_drb->IsEOF())
239  {
240  LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- Device EOF detected");
241  m_bError = true;
242  }
243  else
244  {
245 #if 0 // For this to work, the data needs to be propagated back up to
246  // the 'recorder', but there could be multiple rcorders...
247 
248  // If we have seen good data, but now have a gap, note it
249  if (good_data)
250  {
251  if (gap)
252  {
253  QMutexLocker locker(&statisticsLock);
254  QDateTime gap_end(MythDate::current());
255 
256  for (Irec = m_rec_gaps.begin();
257  Irec != m_rec_caps.end(); ++Irec)
258  {
259  (*Irec).push_back(RecordingGap
260  (gap_start, gap_end));
261  }
262  LOG(VB_RECORD, LOG_DEBUG,
263  LOC + QString("Inserted gap %1 dur %2")
264  .arg(recordingGaps.back().toString())
265  .arg(gap_start.secsTo(gap_end)));
266  gap = false;
267  }
268  else
269  gap_start = MythDate::current();
270  }
271  else
272  good_data = true;
273 #else
274  good_data = true;
275 #endif
276  }
277 
278  if (len < 0)
279  {
280  if (errno != EAGAIN)
281  {
282  LOG(VB_GENERAL, LOG_ERR, LOC +
283  QString("run() -- error reading from: %1")
284  .arg(m_device) + ENO);
285  }
286  continue;
287  }
288 
289  buffer.append(pkt_buf, len);
290  len = buffer.size();
291 
292  if (len < static_cast<int>(TSPacket::kSize))
293  continue;
294 
295  if (!m_listenerLock.tryLock())
296  continue;
297 
298  if (m_streamDataList.empty())
299  {
300  LOG(VB_GENERAL, LOG_ERR, LOC +
301  QString("run() -- _stream_data_list is empty, %1 buffered")
302  .arg(buffer.size()));
303  m_listenerLock.unlock();
304  continue;
305  }
306 
307  int remainder = 0;
308  for (auto sit = m_streamDataList.cbegin(); sit != m_streamDataList.cend(); ++sit)
309  {
310  remainder = sit.key()->ProcessData
311  (reinterpret_cast<const uint8_t *>
312  (buffer.constData()), len);
313  }
314 
315  m_listenerLock.unlock();
316 
317  if (remainder > 0 && (len > remainder)) // leftover bytes
318  buffer.remove(0, len - remainder);
319  else
320  buffer.clear();
321  }
322 
323  QString tmp(m_error);
324  LOG(VB_GENERAL, LOG_WARNING, LOC +
325  QString("_running_desired(%1) _error(%2)")
326  .arg(m_runningDesired).arg(tmp));
327 
328  LOG(VB_RECORD, LOG_INFO, LOC + "run() -- finishing up");
329  StopEncoding();
330 
331  delete[] pkt_buf;
332 
333  SetRunning(false, true, false);
334  RunEpilog();
335 
336  LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end");
337 }
338 
339 
341 {
342  LOG(VB_RECORD, LOG_INFO, LOC + "open() -- begin");
343 
344  if (IsOpen())
345  {
346  LOG(VB_RECORD, LOG_WARNING, LOC + "run() -- Already open.");
347  return true;
348  }
349  Close();
350 
351  QMutexLocker lock(&m_streamLock);
353  if (!m_v4l2.IsOpen())
354  {
355  m_error = QString("Open of '%1' failed: ").arg(m_device) + ENO;
356  LOG(VB_GENERAL, LOG_ERR, LOC + "Open() -- " + m_error);
357  return false;
358  }
359 
360  if (!m_v4l2.IsEncoder())
361  {
362  m_error = "V4L version 2 required";
363  LOG(VB_GENERAL, LOG_ERR, LOC + "Open() -- " + m_error);
364  m_v4l2.Close();
365  return false;
366  }
367 
368  if (m_drb)
369  {
370  if (m_drb->IsRunning())
371  m_drb->Stop();
372  delete m_drb;
373  m_drb = nullptr;
374  }
375 
376 
377  m_fd = open(m_device.toLatin1().constData(), O_RDWR | O_NONBLOCK);
378 
379  m_drb = new DeviceReadBuffer(this);
380  if (!m_drb)
381  {
382  m_error = "Failed to allocate DRB buffer";
383  LOG(VB_GENERAL, LOG_ERR, LOC + "Configure() -- " + m_error);
384  Close();
385  return false;
386  }
387 
388  m_drb->SetRequestPause(true);
389  if (!m_drb->Setup(m_device.toLatin1().constData(), m_fd))
390  {
391  m_error = "Failed to setup DRB buffer";
392  LOG(VB_GENERAL, LOG_ERR, LOC + "Configure() -- " + m_error);
393  Close();
394  return false;
395  }
396 
397  LOG(VB_RECORD, LOG_INFO, LOC + "open() -- done");
398  return true;
399 }
400 
402 {
403  if (m_streamingCnt.loadRelaxed() > 0)
404  {
405  LOG(VB_RECORD, LOG_INFO, LOC + "Configure() -- Already configured.");
406  return true;
407  }
408 
409  LOG(VB_RECORD, LOG_INFO, LOC + "Configure() -- begin");
410 
411  if (m_width > 0 && m_height > 0 &&
413  {
414  m_v4l2.Close();
415  LOG(VB_RECORD, LOG_ERR, LOC + "Configure() -- failed");
416  return false;
417  }
418 
419  if (m_v4l2.HasTuner())
420  SetLanguageMode(); // we don't care if this fails...
421 
422  if (m_v4l2.HasAudioSupport())
423  m_v4l2.SetVolume(m_audioVolume); // we don't care if this fails...
424 
425  if (m_desiredStreamType >= 0)
427 
428  LOG(VB_RECORD, LOG_INFO, LOC + QString("Options for %1")
430 
431  if (m_aspectRatio >= 0)
433 
434  if (m_bitrateMode < 0)
436  if (m_maxBitrate < 0 && m_highPeakBitrate > 0)
438  if (m_bitrate < 0 && m_highBitrate > 0)
440 
441  m_maxBitrate = std::max(m_maxBitrate, m_bitrate);
442 
443  if (m_bitrateMode >= 0)
445  if (m_bitrate > 0)
447  if (m_maxBitrate > 0)
449 
450  if (m_audioInput >= 0)
452  else
453  LOG(VB_CHANNEL, LOG_WARNING, "Audio input not set.");
454 
455  if (m_audioCodec >= 0)
457  if (m_audioSampleRate >= 0)
459  if (m_audioBitrateL2 >= 0)
461 
462  ConfigureVBI();
463 
464  LOG(VB_RECORD, LOG_INFO, LOC + "Configure() -- done");
465  return false;
466 }
467 
469 {
470 #if 0
471 // VBI
472  if (m_vbi_thread != nullptr)
473  {
474  m_vbi_thread->wait();
475  delete m_vbi_thread;
476  m_vbi_thread = nullptr;
477 
478  CloseVBIDevice();
479  }
480 #endif
481 
482  if (m_drb)
483  {
484  m_drb->Stop();
485  delete m_drb;
486  m_drb = nullptr;
487  }
488 
489  m_v4l2.Close();
490 
491  if (m_fd >= 0)
492  {
493  close(m_fd);
494  m_fd = -1;
495  LOG(VB_RECORD, LOG_INFO, LOC + "Closed.");
496  }
497 
498  m_streamingCnt.fetchAndStoreAcquire(0);
499 }
500 
502 {
503  LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding() -- begin");
504  int old_cnt = 0;
505 
506  QMutexLocker lock(&m_streamLock);
507 
508  if (!IsOpen())
509  {
510  LOG(VB_GENERAL, LOG_ERR, LOC + "V4L2 recorder not initialized.");
511  return false;
512  }
513 
514  if ((old_cnt = m_streamingCnt.loadRelaxed()) == 0)
515  {
516  // Start encoding
517 
518  LOG(VB_GENERAL, LOG_INFO, LOC +
519  QString("Streaming mode %1. Not using it.")
520  .arg(m_v4l2.HasStreaming() ? "available" : "not available"));
521 
523  {
524  for (int idx = 0; idx < 10; ++idx)
525  {
527  break;
528  }
529  }
530 
535 
536  // (at least) with the 3.10 kernel, the V4L2_ENC_CMD_START does
537  // not reliably start the data flow from a HD-PVR. A read() seems
538  // to work, though.
539 
540  int idx = 1;
541  for ( ; idx < 50; ++idx)
542  {
543  uint8_t dummy = 0;
544  int len = read(m_fd, &dummy, 0);
545  if (len >= 0)
546  {
547  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("StartEncoding read %1 bytes").arg(len));
548  break;
549  }
550  if (idx == 20)
551  {
552  LOG(VB_GENERAL, LOG_ERR, LOC +
553  "StartEncoding: read failing, re-opening device: " + ENO);
554  close(m_fd);
555  std::this_thread::sleep_for(2ms);
556  m_fd = open(m_device.toLatin1().constData(), O_RDWR | O_NONBLOCK);
557  if (m_fd < 0)
558  {
559  LOG(VB_GENERAL, LOG_ERR, LOC +
560  "StartEncoding: Can't open video device." + ENO);
561  m_error = "Failed to start recording";
562  return false;
563  }
564  }
565  else
566  {
567  LOG(VB_GENERAL, LOG_ERR, LOC +
568  QString("StartEncoding: read failed, retry in %1 msec:")
569  .arg(100 * idx) + ENO);
570  std::this_thread::sleep_for(idx * 100us);
571  }
572  }
573  if (idx == 50)
574  {
575  LOG(VB_GENERAL, LOG_ERR, LOC +
576  "StartEncoding: read from video device failed." + ENO);
577  m_error = "Failed to start recording";
578  close(m_fd);
579  m_fd = -1;
580  return false;
581  }
582  if (idx > 0)
583  {
584  LOG(VB_RECORD, LOG_WARNING, LOC +
585  QString("%1 read attempts required to start encoding").arg(idx));
586  }
587 
588  if (m_drb)
589  {
590  m_drb->SetRequestPause(false);
591  m_drb->Start();
592  }
593  }
594  else
595  LOG(VB_RECORD, LOG_INFO, LOC + "Already encoding");
596 
597  QMutexLocker listen_lock(&m_listenerLock);
598 
599  m_streamingCnt.ref();
600 
601  LOG(VB_RECORD, LOG_INFO, LOC +
602  QString("StartEncoding() -- %1->%2 listeners")
603  .arg(old_cnt).arg(m_streamingCnt.loadRelaxed()));
604 
605  LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding() -- end");
606 
607  return true;
608 }
609 
611 {
612  int old_cnt = m_streamingCnt.loadRelaxed();
613 
614  if (old_cnt == 0)
615  {
616  LOG(VB_RECORD, LOG_INFO, LOC + "StopEncoding: already stopped.");
617  return true;
618  }
619 
620  QMutexLocker lock(&m_streamLock);
621 
622  if (m_streamingCnt.deref())
623  {
624  LOG(VB_RECORD, LOG_INFO, LOC +
625  QString("StopEncoding() -- delayed, still have %1 listeners")
626  .arg(m_streamingCnt.loadRelaxed()));
627  return true;
628  }
629 
630  if (!IsOpen())
631  {
632  LOG(VB_GENERAL, LOG_ERR, LOC +
633  "StopEncoding() -- V4L2enc recorder not started.");
634  return false;
635  }
636 
637  // Stop encoding
638  if (m_drb)
639  m_drb->SetRequestPause(true);
640 
645 
646  // allow last bits of data through..
647  if (m_drb && m_drb->IsRunning())
648  std::this_thread::sleep_for(20ms);
649 #if 0
650  // close the fd so streamoff/streamon work in V4LChannel Close();
651  close(m_fd);
652 #endif
653 
654  LOG(VB_RECORD, LOG_INFO, LOC +
655  QString("StopEncoding() -- %1->%2 listeners")
656  .arg(old_cnt).arg(m_streamingCnt.loadRelaxed()));
657 
658  return true;
659 }
660 
662 {
663  LOG(VB_RECORD, LOG_INFO, LOC + "RestartEncoding()");
664 
665  StopEncoding();
666  StartEncoding();
667 }
668 
669 #if 0
671 {
672  // TODO report on buffer overruns, etc.
673 }
674 #endif
675 
678 {
679  if (m_langMode < 0)
680  return true;
681 
682  if (V4L2_TUNER_MODE_LANG1_LANG2 == m_langMode &&
683  V4L2_MPEG_AUDIO_ENCODING_LAYER_1 == m_audioLayer)
684  {
685  LOG(VB_GENERAL, LOG_WARNING, LOC +
686  "SetLanguageMode() -- Dual audio mode incompatible "
687  "with Layer I audio. Falling back to Main Language");
688  m_langMode = V4L2_TUNER_MODE_LANG1;
689  }
690 
692 }
693 
694 static int find_index(const std::array<const int,14> &audio_rate, int value)
695 {
696  for (size_t i = 0; i < audio_rate.size(); ++i)
697  {
698  if (audio_rate[i] == value)
699  return i;
700  }
701 
702  return -1;
703 }
704 
705 bool V4L2encStreamHandler::SetOption(const QString &opt, int value)
706 {
707  if (m_streamingCnt.loadRelaxed() > 0)
708  return true;
709 
710  if (opt == "width")
711  m_width = value;
712  else if (opt == "height")
713  m_height = value;
714  else if (opt == "mpeg2bitratemode")
715  {
716  m_bitrateMode = value ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR :
717  V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
718  }
719  else if (opt == "mpeg2bitrate")
720  {
721  m_bitrate = value;
722  }
723  else if (opt == "mpeg2maxbitrate")
724  {
725  m_maxBitrate = value;
726  }
727  else if (opt == "samplerate")
728  {
729  switch (value)
730  {
731  case 32000:
732  m_audioSampleRate = V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
733  break;
734  case 44100:
735  m_audioSampleRate = V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
736  break;
737  case 48000:
738  default:
739  m_audioSampleRate = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
740  }
741  }
742  else if (opt == "mpeg2audbitratel1")
743  {
744  int index = find_index(kAudioRateL1, value);
745  if (index >= 0)
746  m_audioBitrateL1 = index;
747  else
748  {
749  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L1): " +
750  QString("%1 is invalid").arg(value));
751  return true;
752  }
753  }
754  else if (opt == "mpeg2audbitratel2")
755  {
756  int index = find_index(kAudioRateL2, value);
757  if (index >= 0)
758  m_audioBitrateL2 = index;
759  else
760  {
761  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
762  QString("%1 is invalid").arg(value));
763  return true;
764  }
765  }
766  else if (opt == "mpeg2audbitratel3")
767  {
768  int index = find_index(kAudioRateL3, value);
769  if (index >= 0)
770  m_audioBitrateL3 = index;
771  else
772  {
773  LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
774  QString("%1 is invalid").arg(value));
775  return true;
776  }
777  }
778  else if (opt == "mpeg2audvolume")
779  m_audioVolume = value;
780  else if (opt == "low_mpegbitratemode")
781  m_lowBitrateMode = value;
782  else if (opt == "medium_mpegbitratemode")
783  m_mediumBitrateMode = value;
784  else if (opt == "high_mpegbitratemode")
785  m_highBitrateMode = value;
786  else if (opt.endsWith("avgbitrate"))
787  {
788  if (opt.startsWith("low"))
789  m_lowBitrate = value;
790  else if (opt.startsWith("medium"))
791  m_mediumBitrate = value;
792  else if (opt.startsWith("high"))
793  m_highBitrate = value;
794  else
795  return false;
796  }
797  else if (opt.endsWith("peakbitrate"))
798  {
799  if (opt.startsWith("low"))
800  m_lowPeakBitrate = value;
801  else if (opt.startsWith("medium"))
802  m_mediumPeakBitrate = value;
803  else if (opt.startsWith("high"))
804  m_highPeakBitrate = value;
805  else
806  return false;
807  }
808  else
809  return false;
810 
811  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetOption('%1', %2) -- success")
812  .arg(opt).arg(value));
813  return true;
814 }
815 
817 {
818  if (m_streamType == -1)
820  return m_streamType;
821 }
822 
823 bool V4L2encStreamHandler::SetOption(const QString &opt, const QString &value)
824 {
825  if (m_streamingCnt.loadRelaxed() > 0)
826  return true;
827 
828  if (opt == "vbidevice")
829  m_vbiDevice = value;
830  else if (opt == "mpeg2streamtype")
831  {
832  for (size_t i = 0; i < kStreamTypes.size(); ++i)
833  {
834  if (QString::fromStdString(kStreamTypes[i]) == value)
835  {
837  return true;
838  }
839  }
840  LOG(VB_GENERAL, LOG_ERR, LOC +
841  QString("MPEG2 stream type %1 is invalid ").arg(value));
842  return false;
843  }
844  else if (opt == "mpeg2language")
845  {
846  bool ok = false;
847  int lang_mode = value.toInt(&ok); // on failure language will be 0
848  if (!ok)
849  {
850  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 language (stereo) flag " +
851  QString("'%1' is invalid").arg(value));
852  return true;
853  }
854  switch (lang_mode)
855  {
856  case 1:
857  m_langMode = V4L2_TUNER_MODE_LANG2;
858  break;
859  case 2:
860  m_langMode = V4L2_TUNER_MODE_LANG1_LANG2;
861  break;
862  case 0:
863  default:
864  m_langMode = V4L2_TUNER_MODE_LANG1;
865  break;
866  }
867  }
868  else if (opt == "mpeg2aspectratio")
869  {
870  if (value == "Square")
871  m_aspectRatio = V4L2_MPEG_VIDEO_ASPECT_1x1;
872  else if (value == "4:3")
873  m_aspectRatio = V4L2_MPEG_VIDEO_ASPECT_4x3;
874  else if (value == "16:9")
875  m_aspectRatio = V4L2_MPEG_VIDEO_ASPECT_16x9; // NOLINT(bugprone-branch-clone)
876  else if (value == "2.21:1")
877  m_aspectRatio = V4L2_MPEG_VIDEO_ASPECT_221x100;
878  else
879  m_aspectRatio = V4L2_MPEG_VIDEO_ASPECT_16x9;
880  }
881  else if (opt == "mpeg2audtype")
882  {
883  if (value == "Layer I")
884  m_audioLayer = V4L2_MPEG_AUDIO_ENCODING_LAYER_1; // plus one?
885  else if (value == "Layer II")
886  m_audioLayer = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
887  else if (value == "Layer III")
888  m_audioLayer = V4L2_MPEG_AUDIO_ENCODING_LAYER_3;
889  else
890  {
891  LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 audio layer: " +
892  QString("%1 is invalid").arg(value));
893  }
894  }
895  else if (opt == "audiocodec")
896  {
897  if (value.startsWith("V4L2:"))
898  {
899  // Find the value in the options returns by the driver
901  (DriverOption::AUDIO_ENCODING, value.mid(5));
902  }
903  }
904  else
905  return false;
906 
907  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetOption('%1', '%2') -- success")
908  .arg(opt, value));
909  return true;
910 }
911 
913 {
914  if (m_streamingCnt.loadRelaxed() > 0)
915  return true;
916 
917  return true;
918 }
919 
921 {
922  if (m_streamingCnt.loadRelaxed() > 0)
923  {
924  LOG(VB_RECORD, LOG_INFO, LOC + QString("GetSignalStrength() -- "
925  "returning cached value (%1)")
926  .arg(m_signalStrength));
927  return m_signalStrength;
928  }
929 
931  return m_signalStrength;
932 }
933 
934 void V4L2encStreamHandler::SetBitrate(int bitrate, int maxbitrate,
935  int bitratemode, const QString & reason)
936 {
937  if (maxbitrate == bitrate)
938  {
939  LOG(VB_RECORD, LOG_INFO, LOC +
940  QString("SetBitrate() -- %1 bitrate %2 kbps CBR")
941  .arg(reason).arg(bitrate));
942  }
943  else
944  {
945  LOG(VB_RECORD, LOG_INFO, LOC +
946  QString("SetBitrate() -- %1 bitrate %2/%3 kbps VBR")
947  .arg(reason).arg(bitrate).arg(maxbitrate));
948  }
949 
950  // Set VBR or CBR mode
951  if (bitratemode >= 0)
952  m_v4l2.SetVideoBitrateMode(bitratemode);
953 
954  // Set average bitrate
955  if (bitrate > 0)
956  m_v4l2.SetVideoBitrate(bitrate * 1000);
957 
958  // Set max bitrate
959  if (maxbitrate > 0)
960  m_v4l2.SetVideoBitratePeak(maxbitrate * 1000);
961 }
962 
964 {
965  m_width = m_height = -1;
966 
967  int width = 0;
968  int height = 0;
969  int idx = 0;
970  for ( ; idx < 10; ++idx)
971  {
972  if (m_v4l2.GetResolution(width, height))
973  break;
974  if (idx == 5)
975  {
976  m_v4l2.Close();
978  }
979  std::this_thread::sleep_for(100us);
980  }
981  if (idx == 5)
982  return false;
983 
984  m_width = width;
985  m_height = height;
986  int pix = width * height;
987 
988  int old_mode = m_bitrateMode;
989  int old_max = m_maxBitrate;
990  int old_avg = m_bitrate;
991 
992  if (m_lowBitrate > 0 && pix <= 768*1080)
993  {
997  }
998  else if (m_highBitrate > 0 && pix >= 1920*1080)
999  {
1003  }
1004  else if (m_mediumBitrate > 0)
1005  {
1009  }
1010  m_maxBitrate = std::max(m_maxBitrate, m_bitrate);
1011 
1012  if ((old_max != m_maxBitrate) || (old_avg != m_bitrate) ||
1013  old_mode != m_bitrateMode)
1014  {
1015  if (old_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
1016  {
1017  LOG(VB_RECORD, LOG_INFO, LOC +
1018  QString("Old bitrate %1 CBR").arg(old_avg));
1019  }
1020  else
1021  {
1022  LOG(VB_RECORD, LOG_INFO,LOC +
1023  QString("Old bitrate %1/%2 VBR").arg(old_avg).arg(old_max));
1024  }
1025 
1027  }
1028 
1029  return true;
1030 }
1031 
1033 {
1034  LOG(VB_GENERAL, LOG_INFO, LOC + "ConfigureVBI() -- begin");
1035 
1036 
1037  LOG(VB_RECORD, LOG_INFO, LOC + "ConfigureVBI() -- end");
1038 
1039  return false;
1040 }
V4L2encStreamHandler::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: v4l2encstreamhandler.cpp:168
VBIThread
Definition: v4lrecorder.h:62
V4L2encStreamHandler::GetSignalStrength
int GetSignalStrength(void)
Definition: v4l2encstreamhandler.cpp:920
V4L2encStreamHandler::m_audioBitrateL3
int m_audioBitrateL3
Definition: v4l2encstreamhandler.h:115
V4L2encStreamHandler::m_lowBitrate
uint m_lowBitrate
Definition: v4l2encstreamhandler.h:119
V4L2encStreamHandler::Return
static void Return(V4L2encStreamHandler *&ref, int inputid)
Definition: v4l2encstreamhandler.cpp:95
V4L2util::SetAudioBitrateL2
bool SetAudioBitrateL2(int value)
Definition: v4l2util.cpp:1117
V4L2util::StartEncoding
bool StartEncoding(void)
Definition: v4l2util.cpp:1192
O_NONBLOCK
#define O_NONBLOCK
Definition: compat.h:341
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
V4L2encStreamHandler::kAudioRateL2
static const std::array< const int, 14 > kAudioRateL2
Definition: v4l2encstreamhandler.h:129
DeviceReadBuffer::Start
void Start(void)
Definition: DeviceReadBuffer.cpp:106
V4L2util::GetResolution
bool GetResolution(int &width, int &height) const
Definition: v4l2util.cpp:653
DeviceReadBuffer::Setup
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
Definition: DeviceReadBuffer.cpp:49
V4L2encStreamHandler::m_langMode
int m_langMode
0 is Main Lang; 1 is SAP Lang; 2 is Dual
Definition: v4l2encstreamhandler.h:117
V4L2encStreamHandler::m_audioVolume
int m_audioVolume
Definition: v4l2encstreamhandler.h:116
V4L2encStreamHandler
Definition: v4l2encstreamhandler.h:21
V4L2encStreamHandler::IsOpen
bool IsOpen(void) const
Definition: v4l2encstreamhandler.h:46
StreamHandler::SetRunning
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
Definition: streamhandler.cpp:173
V4L2util::SetAudioInput
bool SetAudioInput(int value)
Definition: v4l2util.cpp:923
V4L2encStreamHandler::s_handlers_refcnt
static QMap< QString, uint > s_handlers_refcnt
Definition: v4l2encstreamhandler.h:99
StreamHandler
Definition: streamhandler.h:58
V4L2encStreamHandler::RestartEncoding
void RestartEncoding(void)
Definition: v4l2encstreamhandler.cpp:661
V4L2util::SetVideoBitrate
bool SetVideoBitrate(int value)
Definition: v4l2util.cpp:873
V4L2encStreamHandler::m_highBitrate
uint m_highBitrate
Definition: v4l2encstreamhandler.h:125
V4L2encStreamHandler::m_bitrate
int m_bitrate
Definition: v4l2encstreamhandler.h:108
V4L2encStreamHandler::m_streamLock
QMutex m_streamLock
Definition: v4l2encstreamhandler.h:147
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
V4L2encStreamHandler::HasLock
bool HasLock(void)
Definition: v4l2encstreamhandler.cpp:912
V4L2util::SetLanguageMode
bool SetLanguageMode(int mode)
Definition: v4l2util.cpp:1027
MThread::setObjectName
void setObjectName(const QString &name)
Definition: mthread.cpp:238
V4L2encStreamHandler::m_height
uint m_height
Definition: v4l2encstreamhandler.h:137
V4L2util::SetVideoAspect
bool SetVideoAspect(int value)
Definition: v4l2util.cpp:831
V4L2encStreamHandler::m_fd
int m_fd
Definition: v4l2encstreamhandler.h:133
V4L2util::HasTuner
bool HasTuner(void) const
Definition: v4l2util.cpp:688
DeviceReadBuffer::Read
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
Definition: DeviceReadBuffer.cpp:616
V4L2encStreamHandler::m_audioLayer
int m_audioLayer
Definition: v4l2encstreamhandler.h:111
V4L2encStreamHandler::V4L2encStreamHandler
V4L2encStreamHandler(const QString &device, int audio_input, int inputid)
Definition: v4l2encstreamhandler.cpp:145
V4L2util::StopEncoding
bool StopEncoding(void)
Definition: v4l2util.cpp:1197
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
V4L2encStreamHandler::m_mediumBitrate
uint m_mediumBitrate
Definition: v4l2encstreamhandler.h:122
V4L2encStreamHandler::m_maxBitrate
int m_maxBitrate
Definition: v4l2encstreamhandler.h:109
V4L2encStreamHandler::m_bitrateMode
int m_bitrateMode
Definition: v4l2encstreamhandler.h:107
V4L2encStreamHandler::s_handlers_lock
static QMutex s_handlers_lock
Definition: v4l2encstreamhandler.h:97
streamlisteners.h
V4L2encStreamHandler::Close
void Close(void)
Definition: v4l2encstreamhandler.cpp:468
DeviceReadBuffer
Buffers reads from device files.
Definition: DeviceReadBuffer.h:35
V4L2encStreamHandler::GetStreamType
int GetStreamType(void)
Definition: v4l2encstreamhandler.cpp:816
StreamHandler::m_startStopLock
QMutex m_startStopLock
Definition: streamhandler.h:120
V4L2encStreamHandler::m_audioBitrateL1
int m_audioBitrateL1
Definition: v4l2encstreamhandler.h:113
V4L2encStreamHandler::StopEncoding
bool StopEncoding(void)
Definition: v4l2encstreamhandler.cpp:610
v4l2encstreamhandler.h
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
V4L2encStreamHandler::SetOption
bool SetOption(const QString &opt, int value)
Definition: v4l2encstreamhandler.cpp:705
V4L2encStreamHandler::kAudioRateL1
static const std::array< const int, 14 > kAudioRateL1
Definition: v4l2encstreamhandler.h:128
close
#define close
Definition: compat.h:43
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
V4L2encStreamHandler::SetBitrateForResolution
bool SetBitrateForResolution(void)
Definition: v4l2encstreamhandler.cpp:963
V4L2encStreamHandler::m_highPeakBitrate
uint m_highPeakBitrate
Definition: v4l2encstreamhandler.h:126
StreamHandler::PriorityEvent
void PriorityEvent(int fd) override
Definition: streamhandler.h:99
V4L2encStreamHandler::m_audioBitrateL2
int m_audioBitrateL2
Definition: v4l2encstreamhandler.h:114
V4L2encStreamHandler::Open
bool Open(void)
Definition: v4l2encstreamhandler.cpp:340
StreamHandler::m_listenerLock
QRecursiveMutex m_listenerLock
Definition: streamhandler.h:153
V4L2encStreamHandler::m_signalStrength
uint m_signalStrength
Definition: v4l2encstreamhandler.h:138
V4L2util::SetResolution
bool SetResolution(uint32_t width, uint32_t height)
Definition: v4l2util.cpp:887
V4L2encStreamHandler::m_audioInput
int m_audioInput
Definition: v4l2encstreamhandler.h:134
V4L2util::SetVideoBitratePeak
bool SetVideoBitratePeak(int value)
Definition: v4l2util.cpp:880
V4L2util::UserAdjustableResolution
bool UserAdjustableResolution(void) const
Definition: v4l2util.cpp:707
V4L2util::SetAudioCodec
bool SetAudioCodec(int value)
Definition: v4l2util.cpp:948
V4L2util::SetVolume
bool SetVolume(int volume)
Definition: v4l2util.cpp:992
V4L2encStreamHandler::kStreamTypes
static const std::array< const std::string, 15 > kStreamTypes
Definition: v4l2encstreamhandler.h:131
V4L2encStreamHandler::SetBitrate
void SetBitrate(int bitrate, int maxbitrate, int bitratemode, const QString &reason)
Definition: v4l2encstreamhandler.cpp:934
V4L2encStreamHandler::m_audioCodec
int m_audioCodec
Definition: v4l2encstreamhandler.h:110
V4L2util::StreamTypeDesc
static QString StreamTypeDesc(int value)
Definition: v4l2util.cpp:778
V4L2util::PauseEncoding
bool PauseEncoding(void)
Definition: v4l2util.cpp:1202
find_index
static int find_index(const std::array< const int, 14 > &audio_rate, int value)
Definition: v4l2encstreamhandler.cpp:694
v4lchannel.h
V4L2util::Open
bool Open(const QString &dev_name, const QString &vbi_dev_name="")
Definition: v4l2util.cpp:33
DeviceReadBuffer::IsRunning
bool IsRunning(void) const
Definition: DeviceReadBuffer.cpp:254
V4L2encStreamHandler::m_failing
bool m_failing
Definition: v4l2encstreamhandler.h:90
V4L2encStreamHandler::m_lowPeakBitrate
uint m_lowPeakBitrate
Definition: v4l2encstreamhandler.h:120
V4L2encStreamHandler::StartEncoding
bool StartEncoding(void)
Definition: v4l2encstreamhandler.cpp:501
V4L2encStreamHandler::m_streamType
int m_streamType
Definition: v4l2encstreamhandler.h:105
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
V4L2encStreamHandler::kAudioRateL3
static const std::array< const int, 14 > kAudioRateL3
Definition: v4l2encstreamhandler.h:130
V4L2encStreamHandler::m_aspectRatio
int m_aspectRatio
Definition: v4l2encstreamhandler.h:106
DeviceReadBuffer::Stop
void Stop(void)
Definition: DeviceReadBuffer.cpp:149
V4L2encStreamHandler::m_v4l2
V4L2util m_v4l2
Definition: v4l2encstreamhandler.h:140
V4L2util::HasStreaming
bool HasStreaming(void) const
Definition: v4l2util.cpp:93
V4L2encStreamHandler::s_handlers
static QMap< QString, V4L2encStreamHandler * > s_handlers
Definition: v4l2encstreamhandler.h:98
uint
unsigned int uint
Definition: compat.h:81
mpegstreamdata.h
V4L2encStreamHandler::m_streamingCnt
QAtomicInt m_streamingCnt
Definition: v4l2encstreamhandler.h:146
V4L2util::SetStreamType
bool SetStreamType(int value)
Definition: v4l2util.cpp:817
V4L2encStreamHandler::m_audioSampleRate
int m_audioSampleRate
Definition: v4l2encstreamhandler.h:112
V4L2encStreamHandler::m_vbiDevice
QString m_vbiDevice
Definition: v4l2encstreamhandler.h:144
V4L2util::HasAudioSupport
bool HasAudioSupport(void) const
Definition: v4l2util.cpp:693
LOC
#define LOC
Definition: v4l2encstreamhandler.cpp:57
V4L2encStreamHandler::Status
bool Status(bool &failed, bool &failing)
Definition: v4l2encstreamhandler.cpp:138
V4L2util::IsOpen
bool IsOpen(void) const
Definition: v4l2util.h:29
V4L2encStreamHandler::m_drb
DeviceReadBuffer * m_drb
Definition: v4l2encstreamhandler.h:141
V4L2encStreamHandler::m_mediumPeakBitrate
uint m_mediumPeakBitrate
Definition: v4l2encstreamhandler.h:123
RecordingGap
Definition: recordingquality.h:14
V4L2encStreamHandler::m_mediumBitrateMode
uint m_mediumBitrateMode
Definition: v4l2encstreamhandler.h:121
cardutil.h
StreamHandler::m_runningDesired
volatile bool m_runningDesired
Definition: streamhandler.h:121
V4L2util::GetOptionValue
int GetOptionValue(DriverOption::category_t cat, const QString &desc)
Definition: v4l2util.cpp:564
StreamHandler::m_runningStateChanged
QWaitCondition m_runningStateChanged
Definition: streamhandler.h:131
V4L2util::SetVideoBitrateMode
bool SetVideoBitrateMode(int value)
Definition: v4l2util.cpp:856
V4L2util::SetAudioSamplingRate
bool SetAudioSamplingRate(int value)
Definition: v4l2util.cpp:1080
StreamHandler::m_streamDataList
StreamDataList m_streamDataList
Definition: streamhandler.h:155
DeviceReadBuffer::IsErrored
bool IsErrored(void) const
Definition: DeviceReadBuffer.cpp:242
V4L2encStreamHandler::m_desiredStreamType
int m_desiredStreamType
Definition: v4l2encstreamhandler.h:104
V4L2encStreamHandler::~V4L2encStreamHandler
~V4L2encStreamHandler(void) override
Definition: v4l2encstreamhandler.cpp:162
DriverOption::AUDIO_ENCODING
@ AUDIO_ENCODING
Definition: driveroption.h:12
V4L2encStreamHandler::m_pauseEncodingAllowed
bool m_pauseEncodingAllowed
Definition: v4l2encstreamhandler.h:149
StreamHandler::m_bError
volatile bool m_bError
Definition: streamhandler.h:126
DeviceReadBuffer::IsEOF
bool IsEOF(void) const
Definition: DeviceReadBuffer.cpp:248
V4L2util::ResumeEncoding
bool ResumeEncoding(void)
Definition: v4l2util.cpp:1207
V4L2util::IsEncoder
bool IsEncoder(void) const
Definition: v4l2util.cpp:698
DeviceReadBuffer::SetRequestPause
void SetRequestPause(bool request)
Definition: DeviceReadBuffer.cpp:163
V4L2encStreamHandler::Get
static V4L2encStreamHandler * Get(const QString &devname, int audioinput, int inputid)
Definition: v4l2encstreamhandler.cpp:63
V4L2encStreamHandler::m_width
uint m_width
Definition: v4l2encstreamhandler.h:136
StreamHandler::IsRunning
bool IsRunning(void) const
Definition: streamhandler.cpp:163
V4L2util::GetStreamType
int GetStreamType(void) const
Definition: v4l2util.cpp:798
exitcodes.h
StreamHandler::m_device
QString m_device
Definition: streamhandler.h:113
V4L2util::Close
void Close(void)
Definition: v4l2util.cpp:82
V4L2encStreamHandler::PACKET_SIZE
@ PACKET_SIZE
Definition: v4l2encstreamhandler.h:26
V4L2encStreamHandler::m_error
QString m_error
Definition: v4l2encstreamhandler.h:91
V4L2encStreamHandler::SetLanguageMode
bool SetLanguageMode(void)
Set audio language mode.
Definition: v4l2encstreamhandler.cpp:677
dtvsignalmonitor.h
V4L2encStreamHandler::m_highBitrateMode
uint m_highBitrateMode
Definition: v4l2encstreamhandler.h:124
V4L2encStreamHandler::ConfigureVBI
bool ConfigureVBI(void)
Definition: v4l2encstreamhandler.cpp:1032
V4L2util::GetSignalStrength
int GetSignalStrength(void) const
Definition: v4l2util.cpp:632
V4L2encStreamHandler::Configure
bool Configure(void)
Definition: v4l2encstreamhandler.cpp:401
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:259
V4L2encStreamHandler::m_lowBitrateMode
uint m_lowBitrateMode
Definition: v4l2encstreamhandler.h:118