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