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