MythTV  master
NuppelVideoRecorder.cpp
Go to the documentation of this file.
1 #include <cerrno>
2 #include <cmath>
3 #include <cstdio>
4 #include <cstdlib>
5 #include <fcntl.h>
6 #include <limits> // workaround QTBUG-90395
7 #include <sys/ioctl.h>
8 #include <sys/mman.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
13 #include <QStringList>
14 #include <QtEndian>
15 
16 #include "libmyth/mythcontext.h"
20 
21 #include "NuppelVideoRecorder.h"
22 #include "audioinput.h"
23 #include "channelbase.h"
24 #include "fourcc.h"
25 #include "mythavutil.h"
26 #include "mythsystemevent.h"
27 #include "recorders/vbitext/cc.h"
28 #include "recorders/vbitext/vbi.h"
29 #include "recordingprofile.h"
30 #include "tv_play.h"
31 #include "tv_rec.h"
32 
33 #if HAVE_BIGENDIAN
34 extern "C" {
35 #ifndef MYTHTV_BSWAP_H
36 #define MYTHTV_BSWAP_H
37 
38 #include <cstdint> /* uint32_t */
39 
40 #define bswap_dbl(x) bswap_64(x)
41 
42 #if HAVE_BYTESWAP_H
43 # include <byteswap.h> /* bswap_16|32|64 */
44 #elif HAVE_SYS_ENDIAN_H
45 # include <sys/endian.h>
46 # if !defined(bswap_16) && defined(bswap16)
47 # define bswap_16(x) bswap16(x)
48 # endif
49 # if !defined(bswap_32) && defined(bswap32)
50 # define bswap_32(x) bswap32(x)
51 # endif
52 # if !defined(bswap_64) && defined(bswap64)
53 # define bswap_64(x) bswap64(x)
54 # endif
55 #elif CONFIG_DARWIN
56 # include <libkern/OSByteOrder.h>
57 # define bswap_16(x) OSSwapInt16(x)
58 # define bswap_32(x) OSSwapInt32(x)
59 # define bswap_64(x) OSSwapInt64(x)
60 #elif HAVE_BIGENDIAN
61 # error Byte swapping functions not defined for this platform
62 #endif
63 
64 #endif /* ndef MYTHTV_BSWAP_H */
65 }
66 #endif
67 
68 extern "C" {
69 #include "libswscale/swscale.h"
70 #include "libavutil/imgutils.h"
71 }
72 
73 #ifdef USING_V4L2
74 #include <linux/videodev2.h>
75 #include "go7007_myth.h"
76 #endif // USING_V4L2
77 
78 #include "io/mythmediabuffer.h"
79 #include "RTjpegN.h"
80 
81 #define LOC QString("NVR(%1): ").arg(m_videodevice)
82 
84 {
85  RunProlog();
87  RunEpilog();
88 }
89 
91 {
92  RunProlog();
94  RunEpilog();
95 }
96 
98  V4LRecorder(rec)
99 {
100  m_channelObj = channel;
101  m_seekTable = new std::vector<struct seektable_entry>;
102  m_ccd = new CC608Decoder(this);
103 
105 
107 }
108 
110 {
112  {
113  delete m_ringBuffer;
114  m_ringBuffer = nullptr;
115  }
116  delete m_rtjc;
117  delete [] m_mp3Buf;
118  if (m_gf)
119  lame_close(m_gf);
120  delete [] m_strm;
121  if (m_audioDevice)
122  {
123  delete m_audioDevice;
124  m_audioDevice = nullptr;
125  }
126  if (m_fd >= 0)
127  close(m_fd);
128  if (m_seekTable)
129  {
130  m_seekTable->clear();
131  delete m_seekTable;
132  }
133 
134  while (!m_videoBuffer.empty())
135  {
136  struct vidbuffertype *vb = m_videoBuffer.back();
137  delete [] vb->buffer;
138  delete vb;
139  m_videoBuffer.pop_back();
140  }
141  while (!m_audioBuffer.empty())
142  {
143  struct audbuffertype *ab = m_audioBuffer.back();
144  delete [] ab->buffer;
145  delete ab;
146  m_audioBuffer.pop_back();
147  }
148  while (!m_textBuffer.empty())
149  {
150  struct txtbuffertype *tb = m_textBuffer.back();
151  delete [] tb->buffer;
152  delete tb;
153  m_textBuffer.pop_back();
154  }
155 
156  if (m_mpaVidCodec)
157  avcodec_free_context(&m_mpaVidCtx);
158 
159  delete m_ccd;
160 }
161 
162 void NuppelVideoRecorder::SetOption(const QString &opt, int value)
163 {
164  if (opt == "width")
165  m_wOut = m_width = value;
166  else if (opt == "height")
167  m_hOut = m_height = value;
168  else if (opt == "rtjpegchromafilter")
169  m_m1 = value;
170  else if (opt == "rtjpeglumafilter")
171  m_m2 = value;
172  else if (opt == "rtjpegquality")
173  m_q = value;
174  else if ((opt == "mpeg4bitrate") || (opt == "mpeg2bitrate"))
175  m_targetBitRate = value;
176  else if (opt == "scalebitrate")
177  m_scaleBitRate = value;
178  else if (opt == "mpeg4maxquality")
179  {
180  if (value > 0)
181  m_maxQuality = value;
182  else
183  m_maxQuality = 1;
184  }
185  else if (opt == "mpeg4minquality")
186  m_minQuality = value;
187  else if (opt == "mpeg4qualdiff")
188  m_qualDiff = value;
189  else if (opt == "encodingthreadcount")
190  m_encodingThreadCount = value;
191  else if (opt == "mpeg4optionvhq")
192  {
193  if (value)
194  m_mbDecision = FF_MB_DECISION_RD;
195  else
196  m_mbDecision = FF_MB_DECISION_SIMPLE;
197  }
198  else if (opt == "mpeg4option4mv")
199  {
200  if (value)
201  m_mp4Opts |= AV_CODEC_FLAG_4MV;
202  else
203  m_mp4Opts &= ~AV_CODEC_FLAG_4MV;
204  }
205  else if (opt == "mpeg4optionidct")
206  {
207  if (value)
208  m_mp4Opts |= AV_CODEC_FLAG_INTERLACED_DCT;
209  else
210  m_mp4Opts &= ~AV_CODEC_FLAG_INTERLACED_DCT;
211  }
212  else if (opt == "mpeg4optionime")
213  {
214  if (value)
215  m_mp4Opts |= AV_CODEC_FLAG_INTERLACED_ME;
216  else
217  m_mp4Opts &= ~AV_CODEC_FLAG_INTERLACED_ME;
218  }
219  else if (opt == "hardwaremjpegquality")
220  m_hmjpgQuality = value;
221  else if (opt == "hardwaremjpeghdecimation")
222  m_hmjpgHDecimation = value;
223  else if (opt == "hardwaremjpegvdecimation")
224  m_hmjpgVDecimation = value;
225  else if (opt == "audiocompression")
226  m_compressAudio = (value != 0);
227  else if (opt == "mp3quality")
228  m_mp3Quality = value;
229  else if (opt == "samplerate")
230  m_audioSampleRate = value;
231  else if (opt == "audioframesize")
232  m_audioBufferSize = value;
233  else if (opt == "pip_mode")
234  m_pipMode = value;
235  else if (opt == "inpixfmt")
236  m_inPixFmt = (VideoFrameType)value;
237  else if (opt == "skipbtaudio")
238  m_skipBtAudio = (value != 0);
239  else if (opt == "volume")
240  m_volume = value;
241  else
242  V4LRecorder::SetOption(opt, value);
243 }
244 
245 void NuppelVideoRecorder::SetOption(const QString &name, const QString &value)
246 {
247  V4LRecorder::SetOption(name, value);
248 }
249 
251  const QString &videodev,
252  const QString &audiodev,
253  const QString &vbidev)
254 {
255  SetOption("videodevice", videodev);
256  SetOption("vbidevice", vbidev);
257  SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
258  SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
259  SetOption("audiodevice", audiodev);
260 
261  QString setting;
262  const StandardSetting *tmp = profile->byName("videocodec");
263  if (tmp)
264  setting = tmp->getValue();
265 
266  if (setting == "MPEG-4")
267  {
268  SetOption("videocodec", "mpeg4");
269 
270  SetIntOption(profile, "mpeg4bitrate");
271  SetIntOption(profile, "scalebitrate");
272  SetIntOption(profile, "mpeg4maxquality");
273  SetIntOption(profile, "mpeg4minquality");
274  SetIntOption(profile, "mpeg4qualdiff");
275 #ifdef USING_FFMPEG_THREADS
276  SetIntOption(profile, "encodingthreadcount");
277 #endif
278  SetIntOption(profile, "mpeg4optionvhq");
279  SetIntOption(profile, "mpeg4option4mv");
280  SetIntOption(profile, "mpeg4optionidct");
281  SetIntOption(profile, "mpeg4optionime");
282  }
283  else if (setting == "MPEG-2")
284  {
285  SetOption("videocodec", "mpeg2video");
286 
287  SetIntOption(profile, "mpeg2bitrate");
288  SetIntOption(profile, "scalebitrate");
289 #ifdef USING_FFMPEG_THREADS
290  SetIntOption(profile, "encodingthreadcount");
291 #endif
292  }
293  else if (setting == "RTjpeg")
294  {
295  SetOption("videocodec", "rtjpeg");
296 
297  SetIntOption(profile, "rtjpegquality");
298  SetIntOption(profile, "rtjpegchromafilter");
299  SetIntOption(profile, "rtjpeglumafilter");
300  }
301  else if (setting == "Hardware MJPEG")
302  {
303  SetOption("videocodec", "hardware-mjpeg");
304 
305  SetIntOption(profile, "hardwaremjpegquality");
306  SetIntOption(profile, "hardwaremjpeghdecimation");
307  SetIntOption(profile, "hardwaremjpegvdecimation");
308  }
309  else
310  {
311  LOG(VB_GENERAL, LOG_ERR, LOC +
312  "Unknown video codec. "
313  "Please go into the TV Settings, Recording Profiles and "
314  "setup the four 'Software Encoders' profiles. "
315  "Assuming RTjpeg for now.");
316 
317  SetOption("videocodec", "rtjpeg");
318 
319  SetIntOption(profile, "rtjpegquality");
320  SetIntOption(profile, "rtjpegchromafilter");
321  SetIntOption(profile, "rtjpeglumafilter");
322  }
323 
324  setting.clear();
325  tmp = profile->byName("audiocodec");
326  if (tmp != nullptr)
327  setting = tmp->getValue();
328 
329  if (setting == "MP3")
330  {
331  SetOption("audiocompression", 1);
332  SetIntOption(profile, "mp3quality");
333  SetIntOption(profile, "samplerate");
334  }
335  else if (setting == "Uncompressed")
336  {
337  SetOption("audiocompression", 0);
338  SetIntOption(profile, "samplerate");
339  }
340  else
341  {
342  LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown audio codec");
343  SetOption("audiocompression", 0);
344  }
345 
346  SetIntOption(profile, "volume");
347 
348  SetIntOption(profile, "width");
349  SetIntOption(profile, "height");
350 }
351 
353 {
354  QMutexLocker locker(&m_pauseLock);
357  m_requestPause = true;
358 
359  // The wakeAll is to make sure [write|audio|main]paused are
360  // set immediately, even if we were already paused previously.
361  m_unpauseWait.wakeAll();
362 }
363 
364 bool NuppelVideoRecorder::IsPaused(bool holding_lock) const
365 {
366  if (!holding_lock)
367  m_pauseLock.lock();
368  bool ret = m_audioPaused && m_mainPaused && m_writePaused;
369  if (!holding_lock)
370  m_pauseLock.unlock();
371  return ret;
372 }
373 
374 void NuppelVideoRecorder::SetVideoFilters(QString& /*filters*/)
375 {
376 }
377 
379 {
380  return m_recording;
381 }
382 
384 {
385  return m_framesWritten;
386 }
387 
389 {
390  return m_channelFd;
391 }
392 
394 {
395  if (!m_useAvCodec)
396  m_useAvCodec = true;
397 
398  if (m_mpaVidCodec)
399  avcodec_free_context(&m_mpaVidCtx);
400 
401  QByteArray vcodec = m_videocodec.toLatin1();
402  m_mpaVidCodec = avcodec_find_encoder_by_name(vcodec.constData());
403 
404  if (!m_mpaVidCodec)
405  {
406  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Video Codec not found: %1")
407  .arg(vcodec.constData()));
408  return false;
409  }
410 
411  m_mpaVidCtx = avcodec_alloc_context3(nullptr);
412 
413  switch (m_pictureFormat)
414  {
415  case AV_PIX_FMT_YUV420P:
416  case AV_PIX_FMT_YUV422P:
417  case AV_PIX_FMT_YUVJ420P:
418  m_mpaVidCtx->pix_fmt = m_pictureFormat;
419  break;
420  default:
421  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown picture format: %1")
422  .arg(m_pictureFormat));
423  }
424 
425  m_mpaVidCtx->width = m_wOut;
426  m_mpaVidCtx->height = (int)(m_height * m_heightMultiplier);
427 
428  int usebitrate = m_targetBitRate * 1000;
429  if (m_scaleBitRate)
430  {
431  float diff = (m_wOut * m_hOut) / (640.0 * 480.0);
432  usebitrate = (int)(diff * usebitrate);
433  }
434 
435  if (m_targetBitRate == -1)
436  usebitrate = -1;
437 
438  m_mpaVidCtx->time_base.den = (int)ceil(m_videoFrameRate * 100 *
440  m_mpaVidCtx->time_base.num = 100;
441 
442  // avcodec needs specific settings for mpeg2 compression
443  switch (m_mpaVidCtx->time_base.den)
444  {
445  case 2397:
446  case 2398: m_mpaVidCtx->time_base.den = 24000;
447  m_mpaVidCtx->time_base.num = 1001;
448  break;
449  case 2997:
450  case 2998: m_mpaVidCtx->time_base.den = 30000;
451  m_mpaVidCtx->time_base.num = 1001;
452  break;
453  case 5994:
454  case 5995: m_mpaVidCtx->time_base.den = 60000;
455  m_mpaVidCtx->time_base.num = 1001;
456  break;
457  }
458 
459  AVDictionary *opts = nullptr;
460 
461  m_mpaVidCtx->bit_rate = usebitrate;
462  m_mpaVidCtx->bit_rate_tolerance = usebitrate * 100;
463  m_mpaVidCtx->qmin = m_maxQuality;
464  m_mpaVidCtx->qmax = m_minQuality;
465  m_mpaVidCtx->max_qdiff = m_qualDiff;
466  m_mpaVidCtx->flags = m_mp4Opts;
467  m_mpaVidCtx->mb_decision = m_mbDecision;
468 
469  m_mpaVidCtx->qblur = 0.5;
470  m_mpaVidCtx->max_b_frames = 0;
471  m_mpaVidCtx->b_quant_factor = 0;
472  av_dict_set(&opts, "rc_strategy", "2", 0);
473  av_dict_set(&opts, "b_strategy", "0", 0);
474  m_mpaVidCtx->gop_size = 30;
475  m_mpaVidCtx->rc_max_rate = 0;
476  m_mpaVidCtx->rc_min_rate = 0;
477  m_mpaVidCtx->rc_buffer_size = 0;
478  m_mpaVidCtx->rc_override_count = 0;
479  av_dict_set(&opts, "rc_init_cplx", "0", 0);
480  m_mpaVidCtx->dct_algo = FF_DCT_AUTO;
481  m_mpaVidCtx->idct_algo = FF_IDCT_AUTO;
482  if (m_videocodec.toLower() == "huffyuv" || m_videocodec.toLower() == "mjpeg")
483  m_mpaVidCtx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
484  m_mpaVidCtx->thread_count = m_encodingThreadCount;
485 
486  if (avcodec_open2(m_mpaVidCtx, m_mpaVidCodec, &opts) < 0)
487  {
488  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open FFMPEG/%1 codec")
489  .arg(m_videocodec));
490  return false;
491  }
492 
493 
494  return true;
495 }
496 
498 {
499  m_pictureFormat = AV_PIX_FMT_YUV420P;
500 
501  m_rtjc = new RTjpeg();
502  int setval = RTJ_YUV420;
503  m_rtjc->SetFormat(&setval);
504  setval = (int)(m_hOut * m_heightMultiplier);
505  m_rtjc->SetSize(&m_wOut, &setval);
506  m_rtjc->SetQuality(&m_q);
507  setval = 2;
508  m_rtjc->SetIntra(&setval, &m_m1, &m_m2);
509 }
510 
511 
513 {
514  int tot_height = (int)(m_height * m_heightMultiplier);
515  double aspectnum = m_wOut / (double)tot_height;
516  uint aspect = 0;
517 
518  if (aspectnum == 0.0)
519  aspect = 0;
520  else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
521  aspect = 2;
522  else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
523  aspect = 3;
524  else if (fabs(aspectnum - 2.21) < 0.001)
525  aspect = 4;
526  else
527  aspect = aspectnum * 1000000;
528 
529  if ((aspect > 0) && (aspect != m_videoAspect))
530  {
531  m_videoAspect = aspect;
532  AspectChange((AspectRatio)aspect, 0);
533  }
534 
535  if (m_wOut && tot_height &&
536  ((uint)tot_height != m_videoHeight ||
537  (uint)m_wOut != m_videoWidth))
538  {
539  m_videoHeight = tot_height;
541  ResolutionChange(m_wOut, tot_height, 0);
542  }
543 
544  int den = (int)ceil(m_videoFrameRate * 100 * m_frameRateMultiplier);
545  int num = 100;
546 
547  // avcodec needs specific settings for mpeg2 compression
548  switch (den)
549  {
550  case 2397:
551  case 2398: den = 24000;
552  num = 1001;
553  break;
554  case 2997:
555  case 2998: den = 30000;
556  num = 1001;
557  break;
558  case 5994:
559  case 5995: den = 60000;
560  num = 1001;
561  break;
562  }
563 
564  FrameRate frameRate(den, num);
565  if (frameRate.isNonzero() && frameRate != m_frameRate)
566  {
567  m_frameRate = frameRate;
568  LOG(VB_RECORD, LOG_INFO, LOC + QString("NVR: frame rate = %1")
569  .arg(frameRate.toDouble() * 1000));
570  FrameRateChange(frameRate.toDouble() * 1000, 0);
571  }
572 }
573 
575 {
576  if (AudioInit() != 0)
577  {
578  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init audio input device");
579  }
580 
581  if (m_videocodec == "hardware-mjpeg")
582  {
583  m_videocodec = "mjpeg";
584  m_hardwareEncode = true;
585 
586  MJPEGInit();
587 
589 
590  if (m_ntsc)
591  {
592  switch (m_hmjpgVDecimation)
593  {
594  case 2: m_height = 240; break;
595  case 4: m_height = 120; break;
596  default: m_height = 480; break;
597  }
598  }
599  else
600  {
601  switch (m_hmjpgVDecimation)
602  {
603  case 2: m_height = 288; break;
604  case 4: m_height = 144; break;
605  default: m_height = 576; break;
606  }
607  }
608  }
609 
610  if (!m_ringBuffer)
611  {
612  LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning, old RingBuffer creation");
613  m_ringBuffer = MythMediaBuffer::Create("output.nuv", true);
614  m_weMadeBuffer = true;
615  m_livetv = false;
616  if (!m_ringBuffer || !m_ringBuffer->IsOpen())
617  {
618  m_error = "Could not open RingBuffer";
619  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
620  return;
621  }
622  }
623  else
625 
626  m_audioBytes = 0;
627 
628  InitBuffers();
629 }
630 
631 int NuppelVideoRecorder::AudioInit(bool skipdevice)
632 {
633  if (!skipdevice)
634  {
636  if (!m_audioDevice)
637  {
638  LOG(VB_GENERAL, LOG_ERR, LOC +
639  QString("Failed to create audio device: %1") .arg(m_audioDeviceName));
640  return 1;
641  }
642 
644  {
645  LOG(VB_GENERAL, LOG_ERR, LOC +
646  QString("Failed to open audio device %1").arg(m_audioDeviceName));
647  return 1;
648  }
649 
650  int blocksize = m_audioDevice->GetBlockSize();
651  if (blocksize <= 0)
652  {
653  blocksize = 1024;
654  LOG(VB_GENERAL, LOG_ERR, LOC +
655  QString("Failed to determine audio block size on %1,"
656  "using default 1024 bytes").arg(m_audioDeviceName));
657  }
658 
659  m_audioDevice->Close();
660  m_audioBufferSize = blocksize;
661  }
662 
664  LOG(VB_AUDIO, LOG_INFO, LOC +
665  QString("Audio device %1 buffer size: %1 bytes")
666  .arg(m_audioBufferSize));
667 
668  if (m_compressAudio)
669  {
670  m_gf = lame_init();
671  lame_set_bWriteVbrTag(m_gf, 0);
672  lame_set_quality(m_gf, m_mp3Quality);
673  lame_set_compression_ratio(m_gf, 11);
674  lame_set_mode(m_gf, m_audioChannels == 2 ? STEREO : MONO);
675  lame_set_num_channels(m_gf, m_audioChannels);
676  lame_set_in_samplerate(m_gf, m_audioSampleRate);
677  int tmp = lame_init_params(m_gf);
678  if (tmp != 0)
679  {
680  LOG(VB_GENERAL, LOG_ERR, LOC +
681  QString("AudioInit(): lame_init_params error %1").arg(tmp));
682  m_compressAudio = false;
683  }
684 
685  if (m_audioBits != 16)
686  {
687  LOG(VB_GENERAL, LOG_ERR, LOC +
688  "AudioInit(): lame support requires 16bit audio");
689  m_compressAudio = false;
690  }
691  }
692  m_mp3BufSize = (int)(1.25 * 16384 + 7200);
693  m_mp3Buf = new char[m_mp3BufSize];
694 
695  return 0;
696 }
697 
708 {
709  LOG(VB_GENERAL, LOG_ERR, LOC + "MJPEG not supported by device");
710  return false;
711 }
712 
714 {
715  int videomegs = 0;
716  int audiomegs = 2;
717 
718  if (!m_videoBufferSize)
719  {
720  m_videoBufferSize = static_cast<long>(
722  m_wOut, m_hOut));
723  }
724 
725  if (m_width >= 480 || m_height > 288)
726  videomegs = 20;
727  else
728  videomegs = 12;
729 
730  m_videoBufferCount = (videomegs * 1000 * 1000) / static_cast<int>(m_videoBufferSize);
731 
732  if (m_audioBufferSize != 0)
733  m_audioBufferCount = (audiomegs * 1000 * 1000) / static_cast<int>(m_audioBufferSize);
734  else
735  m_audioBufferCount = 0;
736 
737  m_textBufferSize = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
739 
740  for (int i = 0; i < m_videoBufferCount; i++)
741  {
742  auto *vidbuf = new vidbuffertype;
743  vidbuf->buffer = new unsigned char[m_videoBufferSize];
744  vidbuf->sample = 0;
745  vidbuf->freeToEncode = 0;
746  vidbuf->freeToBuffer = 1;
747  vidbuf->bufferlen = 0;
748  vidbuf->forcekey = false;
749 
750  m_videoBuffer.push_back(vidbuf);
751  }
752 
753  for (int i = 0; i < m_audioBufferCount; i++)
754  {
755  auto *audbuf = new audbuffertype;
756  audbuf->buffer = new unsigned char[m_audioBufferSize];
757  audbuf->sample = 0;
758  audbuf->freeToEncode = 0;
759  audbuf->freeToBuffer = 1;
760 
761  m_audioBuffer.push_back(audbuf);
762  }
763 
764  for (int i = 0; i < m_textBufferCount; i++)
765  {
766  auto *txtbuf = new txtbuffertype;
767  txtbuf->buffer = new unsigned char[m_textBufferSize];
768  txtbuf->freeToEncode = 0;
769  txtbuf->freeToBuffer = 1;
770 
771  m_textBuffer.push_back(txtbuf);
772  }
773 }
774 
776 {
777  for (auto & vidbuf : m_videoBuffer)
778  {
779  delete [] (vidbuf->buffer);
780  vidbuf->buffer = new unsigned char[m_videoBufferSize];
781  }
782 }
783 
785 {
786  delete [] m_strm;
787  m_strm = new signed char[m_width * m_height * 2 + 10];
788 }
789 
791 {
792  if (m_channelFd>0)
793  return true;
794 
795  int retries = 0;
796  QByteArray vdevice = m_videodevice.toLatin1();
797  m_fd = open(vdevice.constData(), O_RDWR);
798  while (m_fd < 0)
799  {
800  usleep(30000);
801  m_fd = open(vdevice.constData(), O_RDWR);
802  if (retries++ > 5)
803  {
804  m_error = QString("Can't open video device: %1").arg(m_videodevice);
805  LOG(VB_GENERAL, LOG_ERR, LOC + m_error + ENO);
806  KillChildren();
807  return false;
808  }
809  }
810 
811  m_channelFd = m_fd;
812  return true;
813 }
814 
816 {
817 #ifdef USING_V4L2
818  m_usingV4l2 = true;
819 
820  struct v4l2_capability vcap {};
821 
822  if (ioctl(m_channelFd, VIDIOC_QUERYCAP, &vcap) < 0)
823  {
824  m_usingV4l2 = false;
825  }
826 
827  if (m_usingV4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
828  {
829  LOG(VB_GENERAL, LOG_ERR, LOC +
830  "Not a v4l2 capture device, falling back to v4l");
831  m_usingV4l2 = false;
832  }
833 
834  if (m_usingV4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
835  {
836  LOG(VB_GENERAL, LOG_ERR, LOC +
837  "Won't work with the streaming interface, falling back");
838  m_usingV4l2 = false;
839  }
840 
841  if (vcap.card[0] == 'B' && vcap.card[1] == 'T' &&
842  vcap.card[2] == '8' && vcap.card[4] == '8')
843  m_correctBttv = true;
844 
845  QString driver = (char *)vcap.driver;
846  if (driver == "go7007")
847  m_go7007 = true;
848 #endif // USING_V4L2
849 }
850 
852 {
853  if (lzo_init() != LZO_E_OK)
854  {
855  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo_init() failed, exiting");
856  m_error = "lzo_init() failed, exiting";
857  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
858  return;
859  }
860 
861  if (!Open())
862  {
863  m_error = "Failed to open device";
864  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
865  return;
866  }
867 
868  ProbeV4L2();
869 
870  if (m_usingV4l2 && !SetFormatV4L2())
871  {
872  m_error = "Failed to set V4L2 format";
873  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
874  return;
875  }
876 
877  StreamAllocate();
878 
879  m_positionMapLock.lock();
880  m_positionMap.clear();
881  m_positionMapDelta.clear();
882  m_positionMapLock.unlock();
883 
884  m_useAvCodec = (m_videocodec.toLower() != "rtjpeg");
885  if (m_useAvCodec)
887 
888  if (!m_useAvCodec)
889  SetupRTjpeg();
890 
892 
893  if (CreateNuppelFile() != 0)
894  {
895  m_error = QString("Cannot open '%1' for writing")
896  .arg(m_ringBuffer->GetFilename());
897  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
898  return;
899  }
900 
901  if (IsHelperRequested())
902  {
903  LOG(VB_GENERAL, LOG_ERR, LOC + "Children are already alive");
904  m_error = "Children are already alive";
905  return;
906  }
907 
908  {
909  QMutexLocker locker(&m_pauseLock);
910  m_requestRecording = true;
911  m_requestHelper = true;
912  m_recording = true;
913  m_recordingWait.wakeAll();
914  }
915 
916  m_writeThread = new NVRWriteThread(this);
917  m_writeThread->start();
918 
919  m_audioThread = new NVRAudioThread(this);
920  m_audioThread->start();
921 
922  if ((m_vbiMode != VBIMode::None) && (OpenVBIDevice() >= 0))
923  m_vbiThread = new VBIThread(this);
924 
925  // save the start time
926  gettimeofday(&m_stm, nullptr);
927 
928  // try to get run at higher scheduling priority, ignore failure
929  myth_nice(-10);
930 
931  if (m_usingV4l2)
932  {
933  m_inPixFmt = FMT_NONE;;
934  DoV4L2();
935  }
936 
937  {
938  QMutexLocker locker(&m_pauseLock);
939  m_requestRecording = false;
940  m_requestHelper = false;
941  m_recording = false;
942  m_recordingWait.wakeAll();
943  }
944 }
945 
946 #ifdef USING_V4L2
948 {
949  struct v4l2_format vfmt {};
950 
951  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
952 
953  vfmt.fmt.pix.width = m_width;
954  vfmt.fmt.pix.height = m_height;
955  vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
956 
957  if (m_go7007)
958  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
959  else if (m_inPixFmt == FMT_YUV422P)
960  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
961  else
962  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
963 
964  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
965  {
966  // this is supported by the cx88 and various ati cards.
967  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
968 
969  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
970  {
971  // this is supported by the HVR-950q
972  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
973  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
974  {
975  LOG(VB_GENERAL, LOG_ERR, LOC +
976  "v4l2: Unable to set desired format");
977  return false;
978  }
979 
980  // we need to convert the buffer - we can't deal with uyvy
981  // directly.
982  if (m_inPixFmt == FMT_YUV422P)
983  {
984  LOG(VB_GENERAL, LOG_ERR, LOC +
985  "v4l2: uyvy format supported, but yuv422 requested.");
986  LOG(VB_GENERAL, LOG_ERR, LOC +
987  "v4l2: unfortunately, this converter hasn't been "
988  "written yet, exiting");
989  return false;
990  }
991  LOG(VB_RECORD, LOG_INFO, LOC +
992  "v4l2: format set, getting uyvy from v4l, converting");
993  }
994  else
995  {
996  // we need to convert the buffer - we can't deal with yuyv directly.
997  if (m_inPixFmt == FMT_YUV422P)
998  {
999  LOG(VB_GENERAL, LOG_ERR, LOC +
1000  "v4l2: yuyv format supported, but yuv422 requested.");
1001  LOG(VB_GENERAL, LOG_ERR, LOC +
1002  "v4l2: unfortunately, this converter hasn't been written "
1003  "yet, exiting");
1004  return false;
1005  }
1006  LOG(VB_RECORD, LOG_INFO, LOC +
1007  "v4l2: format set, getting yuyv from v4l, converting");
1008  }
1009  }
1010  else // cool, we can do our preferred format, most likely running on bttv.
1011  LOG(VB_RECORD, LOG_INFO, LOC +
1012  "v4l2: format set, getting yuv420 from v4l");
1013 
1014  // VIDIOC_S_FMT might change the format, check it
1015  if (m_width != (int)vfmt.fmt.pix.width ||
1016  m_height != (int)vfmt.fmt.pix.height)
1017  {
1018  LOG(VB_RECORD, LOG_INFO, LOC +
1019  QString("v4l2: resolution changed. requested %1x%2, using "
1020  "%3x%4 now")
1021  .arg(m_width).arg(m_height)
1022  .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
1023  m_wOut = m_width = vfmt.fmt.pix.width;
1024  m_hOut = m_height = vfmt.fmt.pix.height;
1025  }
1026 
1027  m_v4l2PixelFormat = vfmt.fmt.pix.pixelformat;
1028 
1029  return true;
1030 }
1031 #else // if !USING_V4L2
1032 bool NuppelVideoRecorder::SetFormatV4L2(void) { return false; }
1033 #endif // !USING_V4L2
1034 
1035 #ifdef USING_V4L2
1036 static constexpr size_t MAX_VIDEO_BUFFERS { 5 };
1038 {
1039  struct v4l2_buffer vbuf {};
1040  struct v4l2_requestbuffers vrbuf {};
1041  struct v4l2_control vc {};
1042 
1043  vc.id = V4L2_CID_AUDIO_MUTE;
1044  vc.value = 0;
1045 
1046  if (ioctl(m_fd, VIDIOC_S_CTRL, &vc) < 0)
1047  LOG(VB_GENERAL, LOG_ERR, LOC +
1048  "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " + ENO);
1049 
1050  if (m_go7007)
1051  {
1052  struct go7007_comp_params comp {};
1053  struct go7007_mpeg_params mpeg {};
1054 
1055  comp.gop_size = m_keyframeDist;
1056  comp.max_b_frames = 0;
1057 
1058  if (fabs(m_videoAspect - 1.33333F) < 0.01F)
1059  {
1060  if (m_ntsc)
1062  else
1064  }
1065  else if (fabs(m_videoAspect - 1.77777F) < 0.01F)
1066  {
1067  if (m_ntsc)
1069  else
1071  }
1072  else
1073  {
1075  }
1076 
1077  comp.flags |= GO7007_COMP_CLOSED_GOP;
1078  if (ioctl(m_fd, GO7007IOC_S_COMP_PARAMS, &comp) < 0)
1079  {
1080  m_error = "Unable to set compression params";
1081  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1082  return;
1083  }
1084 
1085  if (m_videocodec == "mpeg2video")
1086  mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
1087  else
1088  mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
1089 
1090  if (ioctl(m_fd, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0)
1091  {
1092  m_error = "Unable to set MPEG params";
1093  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1094  return;
1095  }
1096 
1097  int usebitrate = m_targetBitRate * 1000;
1098  if (m_scaleBitRate)
1099  {
1100  float diff = (m_width * m_height) / (640.0 * 480.0);
1101  usebitrate = (int)(diff * usebitrate);
1102  }
1103 
1104  if (ioctl(m_fd, GO7007IOC_S_BITRATE, &usebitrate) < 0)
1105  {
1106  m_error = "Unable to set bitrate";
1107  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1108  return;
1109  }
1110 
1111  m_hardwareEncode = true;
1112  }
1113 
1114  uint numbuffers = MAX_VIDEO_BUFFERS;
1115 
1116  vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1117  vrbuf.memory = V4L2_MEMORY_MMAP;
1118  vrbuf.count = numbuffers;
1119 
1120  if (ioctl(m_fd, VIDIOC_REQBUFS, &vrbuf) < 0)
1121  {
1122  m_error = "Not able to get any capture buffers, exiting";
1123  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1124  return;
1125  }
1126 
1127  if (vrbuf.count < numbuffers)
1128  {
1129  LOG(VB_GENERAL, LOG_INFO, LOC +
1130  QString("Requested %1 buffers, but only %2 are available. "
1131  "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
1132  }
1133 
1134  numbuffers = vrbuf.count;
1135 
1136  std::array<uint8_t*,MAX_VIDEO_BUFFERS> buffers {};
1137  std::array<int,MAX_VIDEO_BUFFERS> bufferlen {};
1138 
1139  for (uint i = 0; i < numbuffers; i++)
1140  {
1141  vbuf.type = vrbuf.type;
1142  vbuf.index = i;
1143 
1144  if (ioctl(m_fd, VIDIOC_QUERYBUF, &vbuf) < 0)
1145  {
1146  LOG(VB_GENERAL, LOG_ERR, LOC +
1147  QString("unable to query capture buffer %1").arg(i));
1148  m_error = "Unable to query capture buffer";
1149  return;
1150  }
1151 
1152  buffers[i] = (unsigned char *)mmap(nullptr, vbuf.length,
1153  PROT_READ|PROT_WRITE, MAP_SHARED,
1154  m_fd, vbuf.m.offset);
1155 
1156  if (buffers[i] == MAP_FAILED)
1157  {
1158  LOG(VB_GENERAL, LOG_ERR, LOC + "mmap: " + ENO);
1159  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory map failed");
1160  m_error = "Memory map failed";
1161  return;
1162  }
1163  bufferlen[i] = vbuf.length;
1164  }
1165 
1166  for (uint i = 0; i < numbuffers; i++)
1167  {
1168  memset(buffers[i], 0, bufferlen[i]);
1169  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1170  vbuf.index = i;
1171  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1172  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1173  }
1174 
1175  int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1176  if (ioctl(m_fd, VIDIOC_STREAMON, &turnon) < 0)
1177  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1178 
1179  struct timeval tv {};
1180  fd_set rdset {};
1181  int frame = 0;
1182  bool forcekey = false;
1183 
1184  m_resetCapture = false;
1185 
1186  // setup pixel format conversions for YUYV and UYVY
1187  uint8_t *output_buffer = nullptr;
1188  struct SwsContext *convert_ctx = nullptr;
1189  AVFrame img_out;
1190  if (m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV ||
1191  m_v4l2PixelFormat == V4L2_PIX_FMT_UYVY)
1192  {
1193  AVPixelFormat in_pixfmt = m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV ?
1194  AV_PIX_FMT_YUYV422 :
1195  AV_PIX_FMT_UYVY422;
1196 
1197  output_buffer = (uint8_t*)av_malloc(m_height * m_width * 3 / 2);
1198  if (!output_buffer)
1199  {
1200  m_error = "Cannot initialize image conversion buffer";
1201  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1202  return;
1203  }
1204 
1205  convert_ctx = sws_getCachedContext(convert_ctx, m_width, m_height, in_pixfmt,
1206  m_width, m_height, AV_PIX_FMT_YUV420P,
1207  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1208  if (!convert_ctx)
1209  {
1210  m_error = "Cannot initialize image conversion context";
1211  av_free(output_buffer);
1212  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1213  return;
1214  }
1215 
1216  av_image_fill_arrays(img_out.data, img_out.linesize,
1217  output_buffer, AV_PIX_FMT_YUV420P, m_width, m_height, IMAGE_ALIGN);
1218  }
1219 
1220  while (IsRecordingRequested() && !IsErrored())
1221  {
1222 again:
1223  {
1224  QMutexLocker locker(&m_pauseLock);
1225  if (m_requestPause)
1226  {
1227  if (!m_mainPaused)
1228  {
1229  m_mainPaused = true;
1230  m_pauseWait.wakeAll();
1231  if (IsPaused(true) && m_tvrec)
1233  }
1234  m_unpauseWait.wait(&m_pauseLock, 100);
1235  if (m_clearTimeOnPause)
1236  gettimeofday(&m_stm, nullptr);
1237  continue;
1238  }
1239 
1240  if (!m_requestPause && m_mainPaused)
1241  {
1242  m_mainPaused = false;
1243  m_unpauseWait.wakeAll();
1244  }
1245  }
1246 
1247  if (m_resetCapture)
1248  {
1249  LOG(VB_GENERAL, LOG_ERR, LOC + "Resetting and re-queueing");
1250  turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1251  if (ioctl(m_fd, VIDIOC_STREAMOFF, &turnon) < 0)
1252  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1253 
1254  for (uint i = 0; i < numbuffers; i++)
1255  {
1256  memset(buffers[i], 0, bufferlen[i]);
1257  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1258  vbuf.index = i;
1259  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1260  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1261  }
1262 
1263  if (ioctl(m_fd, VIDIOC_STREAMON, &turnon) < 0)
1264  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1265  m_resetCapture = false;
1266  }
1267 
1268  tv.tv_sec = 5;
1269  tv.tv_usec = 0;
1270  FD_ZERO(&rdset); // NOLINT(readability-isolate-declaration)
1271  FD_SET(m_fd, &rdset);
1272 
1273  switch (select(m_fd+1, &rdset, nullptr, nullptr, &tv))
1274  {
1275  case -1:
1276  if (errno == EINTR)
1277  goto again;
1278  LOG(VB_GENERAL, LOG_ERR, LOC + "select: " + ENO);
1279  continue;
1280  case 0:
1281  LOG(VB_GENERAL, LOG_INFO, LOC + "select timeout");
1282  continue;
1283  default: break;
1284  }
1285 
1286  memset(&vbuf, 0, sizeof(vbuf));
1287  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1288  vbuf.memory = V4L2_MEMORY_MMAP;
1289  if (ioctl(m_fd, VIDIOC_DQBUF, &vbuf) < 0)
1290  {
1291  LOG(VB_GENERAL, LOG_ERR, LOC + "DQBUF ioctl failed." + ENO);
1292 
1293  // EIO failed DQBUF de-tunes post 2.6.15.3 for cx88
1294  // EIO or EINVAL on bttv means we need to reset the buffers..
1295  if (errno == EIO && m_channelObj)
1296  {
1297  m_channelObj->Retune();
1298  m_resetCapture = true;
1299  continue;
1300  }
1301 
1302  if (errno == EIO || errno == EINVAL)
1303  {
1304  m_resetCapture = true;
1305  continue;
1306  }
1307 
1308  if (errno == EAGAIN)
1309  continue;
1310  }
1311 
1312  frame = vbuf.index;
1313  if (m_go7007)
1314  forcekey = ((vbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0U);
1315 
1316  if (!m_requestPause)
1317  {
1318  if ((m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV) &&
1319  (output_buffer != nullptr))
1320  {
1321  AVFrame img_in;
1322  av_image_fill_arrays(img_in.data, img_in.linesize,
1323  buffers[frame], AV_PIX_FMT_YUYV422, m_width, m_height,
1324  IMAGE_ALIGN);
1325  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1326  0, m_height, img_out.data, img_out.linesize);
1327  BufferIt(output_buffer, m_videoBufferSize);
1328  }
1329  else if ((m_v4l2PixelFormat == V4L2_PIX_FMT_UYVY) &&
1330  (output_buffer != nullptr))
1331  {
1332  AVFrame img_in;
1333  av_image_fill_arrays(img_in.data, img_in.linesize,
1334  buffers[frame], AV_PIX_FMT_UYVY422, m_width, m_height,
1335  IMAGE_ALIGN);
1336  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1337  0, m_height, img_out.data, img_out.linesize);
1338  BufferIt(output_buffer, m_videoBufferSize);
1339  }
1340  else
1341  {
1342  // buffer the frame directly
1343  BufferIt(buffers[frame], vbuf.bytesused, forcekey);
1344  }
1345  }
1346 
1347  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1348  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1349  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1350  }
1351 
1352  KillChildren();
1353 
1354  if (ioctl(m_fd, VIDIOC_STREAMOFF, &turnon) < 0)
1355  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1356 
1357  for (uint i = 0; i < numbuffers; i++)
1358  {
1359  munmap(buffers[i], bufferlen[i]);
1360  }
1361 
1362  FinishRecording();
1363 
1364  av_free(output_buffer);
1365  sws_freeContext(convert_ctx);
1366 
1367  close(m_fd);
1368  close(m_channelFd);
1369 }
1370 #else // if !USING_V4L2
1371 void NuppelVideoRecorder::DoV4L2(void) {}
1372 #endif // !USING_V4L2
1373 
1375 {
1376  {
1377  QMutexLocker locker(&m_pauseLock);
1378  m_requestHelper = false;
1379  m_unpauseWait.wakeAll();
1380  }
1381 
1382  if (m_writeThread)
1383  {
1384  m_writeThread->wait();
1385  delete m_writeThread;
1386  m_writeThread = nullptr;
1387  }
1388 
1389  if (m_audioThread)
1390  {
1391  m_audioThread->wait();
1392  delete m_audioThread;
1393  m_audioThread = nullptr;
1394  }
1395 
1396  if (m_vbiThread)
1397  {
1398  m_vbiThread->wait();
1399  delete m_vbiThread;
1400  m_vbiThread = nullptr;
1401  CloseVBIDevice();
1402  }
1403 }
1404 
1405 void NuppelVideoRecorder::BufferIt(unsigned char *buf, int len, bool forcekey)
1406 {
1407  struct timeval now {};
1408 
1409  int act = m_actVideoBuffer;
1410 
1411  if (!m_videoBuffer[act]->freeToBuffer) {
1412  return;
1413  }
1414 
1415  gettimeofday(&now, nullptr);
1416 
1417  auto tcres = durationFromTimevalDelta<std::chrono::milliseconds>(now, m_stm);
1418 
1419  m_useBttv = 0;
1420  // here is the non preferable timecode - drop algorithm - fallback
1421  if (!m_useBttv)
1422  {
1423  if (m_tf==0)
1424  m_tf = 2;
1425  else
1426  {
1427  int fn = (tcres - m_oldTc).count();
1428 
1429  // the difference should be less than 1,5*timeperframe or we have
1430  // missed at least one frame, this code might be inaccurate!
1431 
1432  if (m_ntscFrameRate)
1433  fn = (fn+16)/33;
1434  else
1435  fn = (fn+20)/40;
1436  if (fn<1)
1437  fn=1;
1438  m_tf += 2*fn; // two fields
1439  }
1440  }
1441 
1442  m_oldTc = tcres;
1443 
1444  if (!m_videoBuffer[act]->freeToBuffer)
1445  {
1446  LOG(VB_GENERAL, LOG_INFO, LOC +
1447  "DROPPED frame due to full buffer in the recorder.");
1448  return; // we can't buffer the current frame
1449  }
1450 
1451  m_videoBuffer[act]->sample = m_tf;
1452 
1453  // record the time at the start of this frame.
1454  // 'tcres' is at the end of the frame, so subtract the right # of ms
1455  m_videoBuffer[act]->timecode =
1456  (m_ntscFrameRate) ? (tcres - 33ms) : (tcres - 40ms);
1457 
1458  memcpy(m_videoBuffer[act]->buffer, buf, len);
1459  m_videoBuffer[act]->bufferlen = len;
1460  m_videoBuffer[act]->forcekey = forcekey;
1461 
1462  m_videoBuffer[act]->freeToBuffer = 0;
1463  m_actVideoBuffer++;
1465  m_actVideoBuffer = 0; // cycle to begin of buffer
1466  m_videoBuffer[act]->freeToEncode = 1; // set last to prevent race
1467 }
1468 
1470 {
1471 #if HAVE_BIGENDIAN
1472  fh->timecode = bswap_32(fh->timecode);
1473  fh->packetlength = bswap_32(fh->packetlength);
1474 #endif
1476 }
1477 
1479 {
1480  if (newaspect == static_cast<double>(m_videoAspect))
1481  return;
1482 
1483  m_videoAspect = newaspect;
1484 
1485  struct rtframeheader frameheader {};
1486 
1487  frameheader.frametype = 'S';
1488  frameheader.comptype = 'M';
1489  frameheader.packetlength = sizeof(struct rtfileheader);
1490 
1491  WriteFrameheader(&frameheader);
1492 
1493  WriteFileHeader();
1494 }
1495 
1497 {
1498  struct rtfileheader fileheader {};
1499  static const std::string kFinfo { "MythTVVideo" };
1500  static const std::string kVers { "0.07" };
1501 
1502  std::copy(kFinfo.cbegin(), kFinfo.cend(), fileheader.finfo);
1503  std::copy(kVers.cbegin(), kVers.cend(), fileheader.version);
1504  fileheader.width = m_wOut;
1505  fileheader.height = (int)(m_hOut * m_heightMultiplier);
1506  fileheader.desiredwidth = 0;
1507  fileheader.desiredheight = 0;
1508  fileheader.pimode = 'P';
1509  fileheader.aspect = m_videoAspect;
1510  fileheader.fps = m_videoFrameRate;
1511  fileheader.fps *= m_frameRateMultiplier;
1512  fileheader.videoblocks = -1;
1513  fileheader.audioblocks = -1;
1514  fileheader.textsblocks = -1; // TODO: make only -1 if VBI support active?
1515  fileheader.keyframedist = KEYFRAMEDIST;
1516 
1517 #if HAVE_BIGENDIAN
1518  fileheader.width = bswap_32(fileheader.width);
1519  fileheader.height = bswap_32(fileheader.height);
1520  fileheader.desiredwidth = bswap_32(fileheader.desiredwidth);
1521  fileheader.desiredheight = bswap_32(fileheader.desiredheight);
1522  fileheader.aspect = bswap_dbl(fileheader.aspect);
1523  fileheader.fps = bswap_dbl(fileheader.fps);
1524  fileheader.videoblocks = bswap_32(fileheader.videoblocks);
1525  fileheader.audioblocks = bswap_32(fileheader.audioblocks);
1526  fileheader.textsblocks = bswap_32(fileheader.textsblocks);
1527  fileheader.keyframedist = bswap_32(fileheader.keyframedist);
1528 #endif
1529  m_ringBuffer->Write(&fileheader, FILEHEADERSIZE);
1530 }
1531 
1533 {
1534  struct rtframeheader frameheader {};
1535 
1536  WriteFileHeader();
1537 
1538  frameheader.frametype = 'D'; // compressor data
1539 
1540  if (m_useAvCodec)
1541  {
1542  frameheader.comptype = 'F';
1543  frameheader.packetlength = m_mpaVidCtx->extradata_size;
1544 
1545  WriteFrameheader(&frameheader);
1546  m_ringBuffer->Write(m_mpaVidCtx->extradata, frameheader.packetlength);
1547  }
1548  else
1549  {
1550  static std::array<uint32_t,128> s_tbls {};
1551 
1552  frameheader.comptype = 'R'; // compressor data for RTjpeg
1553  frameheader.packetlength = s_tbls.size() * sizeof(uint32_t);
1554 
1555  // compression configuration header
1556  WriteFrameheader(&frameheader);
1557 
1558  m_ringBuffer->Write(s_tbls.data(), s_tbls.size() * sizeof(uint32_t));
1559  }
1560 
1561  memset(&frameheader, 0, sizeof(frameheader));
1562  frameheader.frametype = 'X'; // extended data
1563  frameheader.packetlength = sizeof(extendeddata);
1564 
1565  // extended data header
1566  WriteFrameheader(&frameheader);
1567 
1568  struct extendeddata moredata {};
1569 
1570  moredata.version = 1;
1571  if (m_useAvCodec)
1572  {
1573  int vidfcc = 0;
1574  switch(m_mpaVidCodec->id)
1575  {
1576  case AV_CODEC_ID_MPEG4: vidfcc = FOURCC_DIVX; break;
1577  case AV_CODEC_ID_WMV1: vidfcc = FOURCC_WMV1; break;
1578  case AV_CODEC_ID_MSMPEG4V3: vidfcc = FOURCC_DIV3; break;
1579  case AV_CODEC_ID_MSMPEG4V2: vidfcc = FOURCC_MP42; break;
1580  case AV_CODEC_ID_MSMPEG4V1: vidfcc = FOURCC_MPG4; break;
1581  case AV_CODEC_ID_MJPEG: vidfcc = FOURCC_MJPG; break;
1582  case AV_CODEC_ID_H263:
1583  case AV_CODEC_ID_H263P: vidfcc = FOURCC_H263; break;
1584  case AV_CODEC_ID_H263I: vidfcc = FOURCC_I263; break;
1585  case AV_CODEC_ID_MPEG1VIDEO: vidfcc = FOURCC_MPEG; break;
1586  case AV_CODEC_ID_MPEG2VIDEO: vidfcc = FOURCC_MPG2; break;
1587  case AV_CODEC_ID_HUFFYUV: vidfcc = FOURCC_HFYU; break;
1588  default: break;
1589  }
1590  moredata.video_fourcc = vidfcc;
1591  moredata.lavc_bitrate = m_mpaVidCtx->bit_rate;
1592  moredata.lavc_qmin = m_mpaVidCtx->qmin;
1593  moredata.lavc_qmax = m_mpaVidCtx->qmax;
1594  moredata.lavc_maxqdiff = m_mpaVidCtx->max_qdiff;
1595  }
1596  else
1597  {
1598  moredata.video_fourcc = FOURCC_RJPG;
1599  moredata.rtjpeg_quality = m_q;
1600  moredata.rtjpeg_luma_filter = m_m1;
1601  moredata.rtjpeg_chroma_filter = m_m2;
1602  }
1603 
1604  if (m_compressAudio)
1605  {
1606  moredata.audio_fourcc = FOURCC_LAME;
1607  moredata.audio_compression_ratio = 11;
1608  moredata.audio_quality = m_mp3Quality;
1609  }
1610  else
1611  {
1612  moredata.audio_fourcc = FOURCC_RAWA;
1613  }
1614 
1616  moredata.audio_channels = m_audioChannels;
1618 
1620 
1621 #if HAVE_BIGENDIAN
1622  moredata.version = bswap_32(moredata.version);
1623  moredata.video_fourcc = bswap_32(moredata.video_fourcc);
1624  moredata.audio_fourcc = bswap_32(moredata.audio_fourcc);
1625  moredata.audio_sample_rate = bswap_32(moredata.audio_sample_rate);
1626  moredata.audio_bits_per_sample = bswap_32(moredata.audio_bits_per_sample);
1627  moredata.audio_channels = bswap_32(moredata.audio_channels);
1628  moredata.audio_compression_ratio = bswap_32(moredata.audio_compression_ratio);
1629  moredata.audio_quality = bswap_32(moredata.audio_quality);
1630  moredata.rtjpeg_quality = bswap_32(moredata.rtjpeg_quality);
1631  moredata.rtjpeg_luma_filter = bswap_32(moredata.rtjpeg_luma_filter);
1632  moredata.rtjpeg_chroma_filter = bswap_32(moredata.rtjpeg_chroma_filter);
1633  moredata.lavc_bitrate = bswap_32(moredata.lavc_bitrate);
1634  moredata.lavc_qmin = bswap_32(moredata.lavc_qmin);
1635  moredata.lavc_qmax = bswap_32(moredata.lavc_qmax);
1636  moredata.lavc_maxqdiff = bswap_32(moredata.lavc_maxqdiff);
1637  moredata.seektable_offset = bswap_64(moredata.seektable_offset);
1638  moredata.keyframeadjust_offset = bswap_64(moredata.keyframeadjust_offset);
1639 #endif
1640  m_ringBuffer->Write(&moredata, sizeof(moredata));
1641 
1642  m_lastBlock = 0;
1643  m_lf = 0; // that resets framenumber so that seeking in the
1644  // continues parts works too
1645 }
1646 
1648 {
1649  int numentries = m_seekTable->size();
1650 
1651  struct rtframeheader frameheader {};
1652  frameheader.frametype = 'Q'; // SeekTable
1653  frameheader.packetlength = sizeof(struct seektable_entry) * numentries;
1654 
1655  long long currentpos = m_ringBuffer->GetWritePosition();
1656 
1657  m_ringBuffer->Write(&frameheader, sizeof(frameheader));
1658 
1659  char *seekbuf = new char[frameheader.packetlength];
1660  int offset = 0;
1661 
1662  for (auto & entry : *m_seekTable)
1663  {
1664  memcpy(seekbuf + offset, (const void *)&entry,
1665  sizeof(struct seektable_entry));
1666  offset += sizeof(struct seektable_entry);
1667  }
1668 
1669  m_ringBuffer->Write(seekbuf, frameheader.packetlength);
1670 
1672  offsetof(struct extendeddata, seektable_offset),
1673  SEEK_SET);
1674 
1675  m_ringBuffer->Write(&currentpos, sizeof(long long));
1676 
1677  m_ringBuffer->WriterSeek(0, SEEK_END);
1678 
1679  delete [] seekbuf;
1680 }
1681 
1683  const std::vector<struct kfatable_entry> &kfa_table)
1684 {
1685  int numentries = kfa_table.size();
1686 
1687  struct rtframeheader frameheader {};
1688  frameheader.frametype = 'K'; // KFA Table
1689  frameheader.packetlength = sizeof(struct kfatable_entry) * numentries;
1690 
1691  long long currentpos = m_ringBuffer->GetWritePosition();
1692 
1693  m_ringBuffer->Write(&frameheader, sizeof(frameheader));
1694 
1695  char *kfa_buf = new char[frameheader.packetlength];
1696  uint offset = 0;
1697 
1698  for (const auto& kfa : kfa_table)
1699  {
1700  memcpy(kfa_buf + offset, &kfa,
1701  sizeof(struct kfatable_entry));
1702  offset += sizeof(struct kfatable_entry);
1703  }
1704 
1705  m_ringBuffer->Write(kfa_buf, frameheader.packetlength);
1706 
1707 
1709  offsetof(struct extendeddata, keyframeadjust_offset),
1710  SEEK_SET);
1711 
1712  m_ringBuffer->Write(&currentpos, sizeof(long long));
1713 
1714  m_ringBuffer->WriterSeek(0, SEEK_END);
1715 
1716  delete [] kfa_buf;
1717 }
1718 
1719 void NuppelVideoRecorder::UpdateSeekTable(int frame_num, long offset)
1720 {
1721  long long position = m_ringBuffer->GetWritePosition() + offset;
1722  struct seektable_entry ste { position, frame_num};
1723  m_seekTable->push_back(ste);
1724 
1725  m_positionMapLock.lock();
1726  if (!m_positionMap.contains(ste.keyframe_number))
1727  {
1728  m_positionMapDelta[ste.keyframe_number] = position;
1729  m_positionMap[ste.keyframe_number] = position;
1730  m_lastPositionMapPos = position;
1731  }
1732  m_positionMapLock.unlock();
1733 }
1734 
1736 {
1737  m_framesWritten = 0;
1738 
1739  if (!m_ringBuffer)
1740  {
1741  LOG(VB_GENERAL, LOG_ERR, LOC +
1742  "No ringbuffer, recorder wasn't initialized.");
1743  return -1;
1744  }
1745 
1746  if (!m_ringBuffer->IsOpen())
1747  {
1748  LOG(VB_GENERAL, LOG_ERR, LOC + "Ringbuffer isn't open");
1749  return -1;
1750  }
1751 
1752  WriteHeader();
1753 
1754  return 0;
1755 }
1756 
1758 {
1759  ResetForNewFile();
1760 
1761  for (int i = 0; i < m_videoBufferCount; i++)
1762  {
1763  vidbuffertype *vidbuf = m_videoBuffer[i];
1764  vidbuf->sample = 0;
1765  vidbuf->timecode = 0ms;
1766  vidbuf->freeToEncode = 0;
1767  vidbuf->freeToBuffer = 1;
1768  vidbuf->forcekey = false;
1769  }
1770 
1771  for (int i = 0; i < m_audioBufferCount; i++)
1772  {
1773  audbuffertype *audbuf = m_audioBuffer[i];
1774  audbuf->sample = 0;
1775  audbuf->timecode = 0ms;
1776  audbuf->freeToEncode = 0;
1777  audbuf->freeToBuffer = 1;
1778  }
1779 
1780  for (int i = 0; i < m_textBufferCount; i++)
1781  {
1782  txtbuffertype *txtbuf = m_textBuffer[i];
1783  txtbuf->freeToEncode = 0;
1784  txtbuf->freeToBuffer = 1;
1785  }
1786 
1787  m_actVideoEncode = 0;
1788  m_actVideoBuffer = 0;
1789  m_actAudioEncode = 0;
1790  m_actAudioBuffer = 0;
1791  m_actAudioSample = 0;
1792  m_actTextEncode = 0;
1793  m_actTextBuffer = 0;
1794 
1795  m_audioBytes = 0;
1796  m_effectiveDsp = 0;
1797 
1798  if (m_useAvCodec)
1800 
1801  if (m_curRecording)
1803 }
1804 
1806 {
1807  if (!m_audioDevice)
1808  {
1809  LOG(VB_GENERAL, LOG_ERR, LOC +
1810  QString("Invalid audio device (%1), exiting").arg(m_audioDeviceName));
1811  return;
1812  }
1813 
1815  {
1816  LOG(VB_GENERAL, LOG_ERR, LOC +
1817  QString("Failed to open audio device %1").arg(m_audioDeviceName));
1818  return;
1819  }
1820 
1821  if (!m_audioDevice->Start())
1822  {
1823  LOG(VB_GENERAL, LOG_ERR, LOC +
1824  QString("Failed to start audio capture on %1").arg(m_audioDeviceName));
1825  return;
1826  }
1827 
1828  struct timeval anow {};
1829  auto *buffer = new unsigned char[m_audioBufferSize];
1831 
1832  while (IsHelperRequested() && !IsErrored())
1833  {
1834  {
1835  QMutexLocker locker(&m_pauseLock);
1836  if (m_requestPause)
1837  {
1838  if (!m_audioPaused)
1839  {
1840  m_audioPaused = true;
1841  m_pauseWait.wakeAll();
1842  if (IsPaused(true) && m_tvrec)
1844  }
1845  m_unpauseWait.wait(&m_pauseLock, 100);
1846  continue;
1847  }
1848 
1849  if (!m_requestPause && m_audioPaused)
1850  {
1851  m_audioPaused = false;
1852  m_unpauseWait.wakeAll();
1853  }
1854  }
1855 
1856  if (!IsHelperRequested() || IsErrored())
1857  break;
1858 
1859  int lastread = m_audioDevice->GetSamples(buffer, m_audioBufferSize);
1860  if (m_audioBufferSize != lastread)
1861  {
1862  LOG(VB_GENERAL, LOG_ERR, LOC +
1863  QString("Short read, %1 of %2 bytes from ")
1864  .arg(lastread).arg(m_audioBufferSize) + m_audioDeviceName);
1865  }
1866 
1867  /* record the current time */
1868  /* Don't assume that the sound device's record buffer is empty
1869  (like we used to.) Measure to see how much stuff is in there,
1870  and correct for it when calculating the timestamp */
1871  gettimeofday(&anow, nullptr);
1872  int bytes_read = std::max(m_audioDevice->GetNumReadyBytes(), 0);
1873 
1874  int act = m_actAudioBuffer;
1875 
1876  if (!m_audioBuffer[act]->freeToBuffer)
1877  {
1878  LOG(VB_GENERAL, LOG_ERR, LOC + "Ran out of free AUDIO buffers :-(");
1879  m_actAudioSample++;
1880  continue;
1881  }
1882 
1883  m_audioBuffer[act]->sample = m_actAudioSample;
1884 
1885  /* calculate timecode. First compute the difference
1886  between now and stm (start time) */
1887  m_audioBuffer[act]->timecode =
1888  durationFromTimevalDelta<std::chrono::milliseconds>(anow, m_stm);
1889  /* We want the timestamp to point to the start of this
1890  audio chunk. So, subtract off the length of the chunk
1891  and the length of audio still in the capture buffer. */
1892  m_audioBuffer[act]->timecode -= millisecondsFromFloat(
1893  (bytes_read + m_audioBufferSize)
1894  * 1000.0 / (m_audioSampleRate * m_audioBytesPerSample));
1895 
1896  memcpy(m_audioBuffer[act]->buffer, buffer, m_audioBufferSize);
1897 
1898  m_audioBuffer[act]->freeToBuffer = 0;
1899  m_actAudioBuffer++;
1901  m_actAudioBuffer = 0;
1902  m_audioBuffer[act]->freeToEncode = 1;
1903 
1904  m_actAudioSample++;
1905  }
1906 
1907  delete [] buffer;
1908 
1909  if (m_audioDevice->IsOpen())
1910  m_audioDevice->Close();
1911 }
1912 
1913 #ifdef USING_V4L2
1915 {
1916  struct timeval tnow {};
1917  gettimeofday(&tnow, nullptr);
1918 
1919  int act = m_actTextBuffer;
1920  if (!m_textBuffer[act]->freeToBuffer)
1921  {
1922  LOG(VB_GENERAL, LOG_ERR, LOC +
1923  QString("Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
1924  return;
1925  }
1926 
1927  // calculate timecode:
1928  // compute the difference between now and stm (start time)
1929  m_textBuffer[act]->timecode =
1930  durationFromTimevalDelta<std::chrono::milliseconds>(tnow, m_stm);
1931  m_textBuffer[act]->pagenr = (vbidata->teletextpage.pgno << 16) +
1932  vbidata->teletextpage.subno;
1933 
1934  unsigned char *inpos = vbidata->teletextpage.data[0];
1935  unsigned char *outpos = m_textBuffer[act]->buffer;
1936  *outpos = 0;
1937  struct teletextsubtitle st {};
1938  std::vector<uint8_t> linebuf {};
1939  linebuf.reserve(VT_WIDTH + 1);
1940 
1941  for (int y = 0; y < VT_HEIGHT; y++)
1942  {
1943  char c = ' ';
1944  char last_c = ' ';
1945  int hid = 0;
1946  int gfx = 0;
1947  int dbl = 0;
1948  int box = 0;
1949  int sep = 0;
1950  int hold = 0;
1951  int visible = 0;
1952  int fg = 7;
1953  int bg = 0;
1954 
1955  for (int x = 0; x < VT_WIDTH; ++x)
1956  {
1957  c = *inpos++;
1958  switch (c)
1959  {
1960  case 0x00 ... 0x07: /* alpha + fg color */
1961  fg = c & 7;
1962  gfx = 0;
1963  sep = 0;
1964  hid = 0;
1965  goto ctrl;
1966  case 0x08: /* flash */
1967  case 0x09: /* steady */
1968  goto ctrl;
1969  case 0x0a: /* end box */
1970  box = 0;
1971  goto ctrl;
1972  case 0x0b: /* start box */
1973  box = 1;
1974  goto ctrl;
1975  case 0x0c: /* normal height */
1976  dbl = 0;
1977  goto ctrl;
1978  case 0x0d: /* double height */
1979  if (y < VT_HEIGHT-2) /* ignored on last 2 lines */
1980  {
1981  dbl = 1;
1982  }
1983  goto ctrl;
1984  case 0x10 ... 0x17: /* gfx + fg color */
1985  fg = c & 7;
1986  gfx = 1;
1987  hid = 0;
1988  goto ctrl;
1989  case 0x18: /* conceal */
1990  hid = 1;
1991  goto ctrl;
1992  case 0x19: /* contiguous gfx */
1993  hid = 0;
1994  sep = 0;
1995  goto ctrl;
1996  case 0x1a: /* separate gfx */
1997  sep = 1;
1998  goto ctrl;
1999  case 0x1c: /* black bf */
2000  bg = 0;
2001  goto ctrl;
2002  case 0x1d: /* new bg */
2003  bg = fg;
2004  goto ctrl;
2005  case 0x1e: /* hold gfx */
2006  hold = 1;
2007  goto ctrl;
2008  case 0x1f: /* release gfx */
2009  hold = 0;
2010  goto ctrl;
2011  case 0x0e: /* SO */
2012  case 0x0f: /* SI */
2013  case 0x1b: /* ESC */
2014  goto ctrl;
2015 
2016  ctrl:
2017  c = ' ';
2018  if (hold && gfx)
2019  c = last_c;
2020  break;
2021  }
2022  if (gfx)
2023  {
2024  if ((c & 0xa0) == 0x20)
2025  {
2026  last_c = c;
2027  c += (c & 0x40) ? 32 : -32;
2028  }
2029  }
2030  if (hid)
2031  c = ' ';
2032 
2033  if (visible || (c != ' '))
2034  {
2035  if (!visible)
2036  {
2037  st.row = y;
2038  st.col = x;
2039  st.dbl = dbl;
2040  st.fg = fg;
2041  st.bg = bg;
2042  linebuf.clear();
2043  }
2044  linebuf.push_back(c);
2045  visible = 1;
2046  }
2047 
2048  (void) box;
2049  (void) sep;
2050  }
2051  if (visible)
2052  {
2053  st.len = linebuf.size() + 1;
2054  int maxlen = 200;
2055  int bufsize = ((outpos - m_textBuffer[act]->buffer + 1) + st.len);
2056  if (bufsize > maxlen)
2057  break;
2058  memcpy(outpos, &st, sizeof(st));
2059  outpos += sizeof(st);
2060  int count = std::max(st.len, static_cast<uint8_t>(41));
2061  std::copy(linebuf.cbegin(), linebuf.cbegin() + count, outpos);
2062  outpos += count;
2063  *outpos = 0;
2064  }
2065  }
2066 
2067  m_textBuffer[act]->bufferlen = outpos - m_textBuffer[act]->buffer + 1;
2068  m_textBuffer[act]->freeToBuffer = 0;
2069  m_actTextBuffer++;
2070  if (m_actTextBuffer >= m_textBufferCount)
2071  m_actTextBuffer = 0;
2072  m_textBuffer[act]->freeToEncode = 1;
2073 }
2074 #else // USING_V4L2
2075 void NuppelVideoRecorder::FormatTT(struct VBIData*) {}
2076 #endif // USING_V4L2
2077 
2079 {
2080  struct timeval tnow {};
2081  gettimeofday (&tnow, nullptr);
2082 
2083  // calculate timecode:
2084  // compute the difference between now and stm (start time)
2085  auto tc = durationFromTimevalDelta<std::chrono::milliseconds>(tnow, m_stm);
2086  m_ccd->FormatCC(tc, code1, code2);
2087 }
2088 
2089 void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
2090  std::chrono::milliseconds timecode, char /*type*/)
2091 {
2092  int act = m_actTextBuffer;
2093  if (!m_textBuffer[act]->freeToBuffer)
2094  {
2095  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Teletext#%1").arg(act) +
2096  " ran out of free TEXT buffers :-(");
2097  return;
2098  }
2099 
2100  m_textBuffer[act]->timecode = timecode;
2101  memcpy(m_textBuffer[act]->buffer, buf, len);
2102  m_textBuffer[act]->bufferlen = len + sizeof(ccsubtitle);
2103 
2104  m_textBuffer[act]->freeToBuffer = 0;
2105  m_actTextBuffer++;
2107  m_actTextBuffer = 0;
2108  m_textBuffer[act]->freeToEncode = 1;
2109 }
2110 
2112 {
2113  while (IsHelperRequested() && !IsErrored())
2114  {
2115  {
2116  QMutexLocker locker(&m_pauseLock);
2117  if (m_requestPause)
2118  {
2119  if (!m_writePaused)
2120  {
2121  m_writePaused = true;
2122  m_pauseWait.wakeAll();
2123  if (IsPaused(true) && m_tvrec)
2125  }
2126  m_unpauseWait.wait(&m_pauseLock, 100);
2127  continue;
2128  }
2129 
2130  if (!m_requestPause && m_writePaused)
2131  {
2132  m_writePaused = false;
2133  m_unpauseWait.wakeAll();
2134  }
2135  }
2136 
2137  if (!IsHelperRequested() || IsErrored())
2138  break;
2139 
2141 
2142  enum
2143  { ACTION_NONE,
2144  ACTION_VIDEO,
2145  ACTION_AUDIO,
2146  ACTION_TEXT
2147  } action = ACTION_NONE;
2148  std::chrono::milliseconds firsttimecode = -1ms;
2149 
2150  if (m_videoBuffer[m_actVideoEncode]->freeToEncode)
2151  {
2152  action = ACTION_VIDEO;
2153  firsttimecode = m_videoBuffer[m_actVideoEncode]->timecode;
2154  }
2155 
2156  if (m_audioBufferCount &&
2157  m_audioBuffer[m_actAudioEncode]->freeToEncode &&
2158  (action == ACTION_NONE ||
2159  (m_audioBuffer[m_actAudioEncode]->timecode < firsttimecode)))
2160  {
2161  action = ACTION_AUDIO;
2162  firsttimecode = m_audioBuffer[m_actAudioEncode]->timecode;
2163  }
2164 
2165  if (m_textBufferCount &&
2166  m_textBuffer[m_actTextEncode]->freeToEncode &&
2167  (action == ACTION_NONE ||
2168  (m_textBuffer[m_actTextEncode]->timecode < firsttimecode)))
2169  {
2170  action = ACTION_TEXT;
2171  }
2172 
2173  switch (action)
2174  {
2175  case ACTION_VIDEO:
2176  {
2178  m_videoBuffer[m_actVideoEncode]->bufferlen,
2179  m_width, m_height);
2180  frame.m_frameNumber = m_videoBuffer[m_actVideoEncode]->sample;
2181  frame.m_timecode = m_videoBuffer[m_actVideoEncode]->timecode;
2182  frame.m_forceKey = m_videoBuffer[m_actVideoEncode]->forcekey;
2183  WriteVideo(&frame);
2184  // Ensure buffer isn't deleted
2185  frame.m_buffer = nullptr;
2186 
2187  m_videoBuffer[m_actVideoEncode]->sample = 0;
2188  m_videoBuffer[m_actVideoEncode]->freeToEncode = 0;
2189  m_videoBuffer[m_actVideoEncode]->freeToBuffer = 1;
2190  m_videoBuffer[m_actVideoEncode]->forcekey = false;
2191  m_actVideoEncode++;
2193  m_actVideoEncode = 0;
2194  break;
2195  }
2196  case ACTION_AUDIO:
2197  {
2200  m_audioBuffer[m_actAudioEncode]->timecode);
2201  if (IsErrored()) {
2202  LOG(VB_GENERAL, LOG_ERR, LOC +
2203  "ACTION_AUDIO cannot be completed due to error.");
2204  StopRecording();
2205  break;
2206  }
2207  m_audioBuffer[m_actAudioEncode]->sample = 0;
2208  m_audioBuffer[m_actAudioEncode]->freeToEncode = 0;
2209  m_audioBuffer[m_actAudioEncode]->freeToBuffer = 1;
2210  m_actAudioEncode++;
2212  m_actAudioEncode = 0;
2213  break;
2214  }
2215  case ACTION_TEXT:
2216  {
2218  m_textBuffer[m_actTextEncode]->bufferlen,
2219  m_textBuffer[m_actTextEncode]->timecode,
2220  m_textBuffer[m_actTextEncode]->pagenr);
2221  m_textBuffer[m_actTextEncode]->freeToEncode = 0;
2222  m_textBuffer[m_actTextEncode]->freeToBuffer = 1;
2223  m_actTextEncode++;
2225  m_actTextEncode = 0;
2226  break;
2227  }
2228  default:
2229  {
2230  usleep(100);
2231  break;
2232  }
2233  }
2234  }
2235 }
2236 
2238 {
2239  m_framesWritten = 0;
2240  m_lf = 0;
2241  m_lastBlock = 0;
2242 
2243  m_seekTable->clear();
2244 
2245  ClearStatistics();
2246 
2247  m_positionMapLock.lock();
2248  m_positionMap.clear();
2249  m_positionMapDelta.clear();
2250  m_positionMapLock.unlock();
2251 
2252  if (m_go7007)
2253  m_resetCapture = true;
2254 }
2255 
2257 {
2258  CreateNuppelFile();
2259 }
2260 
2262 {
2264 
2265  WriteSeekTable();
2266 
2268 
2269  m_positionMapLock.lock();
2270  m_positionMap.clear();
2271  m_positionMapDelta.clear();
2272  m_positionMapLock.unlock();
2273 }
2274 
2276  bool forcekey)
2277 {
2278  int tmp = 0;
2279  lzo_uint out_len = kOutLen;
2280  struct rtframeheader frameheader {};
2281  int raw = 0;
2282  int compressthis = m_compression;
2283  std::array<uint8_t*,3> planes {
2284  frame->m_buffer + frame->m_offsets[0],
2285  frame->m_buffer + frame->m_offsets[1],
2286  frame->m_buffer + frame->m_offsets[2] };
2287  int fnum = frame->m_frameNumber;
2288  std::chrono::milliseconds timecode = frame->m_timecode;
2289 
2290  if (m_lf == 0)
2291  { // this will be triggered every new file
2292  m_lf = fnum;
2293  m_startNum = fnum;
2294  m_lastTimecode = 0;
2295  m_frameOfGop = 0;
2296  forcekey = true;
2297  }
2298 
2299  // see if it's time for a seeker header, sync information and a keyframe
2300  frameheader.keyframe = m_frameOfGop; // no keyframe defaulted
2301 
2302  bool wantkeyframe = forcekey;
2303 
2304  bool writesync = false;
2305 
2306  if ((!m_go7007 && (((fnum-m_startNum)>>1) % m_keyframeDist == 0 && !skipsync)) ||
2307  (m_go7007 && frame->m_forceKey))
2308  writesync = true;
2309 
2310  if (writesync)
2311  {
2312  m_ringBuffer->Write("RTjjjjjjjjjjjjjjjjjjjjjjjj", FRAMEHEADERSIZE);
2313 
2314  UpdateSeekTable(((fnum - m_startNum) >> 1) / m_keyframeDist);
2315 
2316  frameheader.frametype = 'S'; // sync frame
2317  frameheader.comptype = 'V'; // video sync information
2318  frameheader.filters = 0; // no filters applied
2319  frameheader.packetlength = 0; // no data packet
2320  frameheader.timecode = (fnum-m_startNum)>>1;
2321  // write video sync info
2322  WriteFrameheader(&frameheader);
2323  frameheader.frametype = 'S'; // sync frame
2324  frameheader.comptype = 'A'; // video sync information
2325  frameheader.filters = 0; // no filters applied
2326  frameheader.packetlength = 0; // no data packet
2327  frameheader.timecode = m_effectiveDsp; // effective dsp frequency
2328  // write audio sync info
2329  WriteFrameheader(&frameheader);
2330 
2331  wantkeyframe = true;
2332  //m_ringBuffer->Sync();
2333  }
2334 
2335  if (wantkeyframe)
2336  {
2337  frameheader.keyframe=0;
2338  m_frameOfGop=0;
2339  }
2340 
2341  if (m_useAvCodec)
2342  {
2343  MythAVFrame mpa_picture;
2344  MythAVUtil::FillAVFrame(mpa_picture, frame);
2345 
2346  if (wantkeyframe)
2347  mpa_picture->pict_type = AV_PICTURE_TYPE_I;
2348  else
2349  mpa_picture->pict_type = AV_PICTURE_TYPE_NONE;
2350 
2351  if (!m_hardwareEncode)
2352  {
2353  AVPacket *packet = av_packet_alloc();
2354  if (packet == nullptr)
2355  {
2356  LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
2357  return;
2358  }
2359  packet->data = (uint8_t *)m_strm;
2360  packet->size = frame->m_bufferSize;
2361 
2362  bool got_packet = false;
2363  int ret = avcodec_receive_packet(m_mpaVidCtx, packet);
2364  if (ret == 0)
2365  got_packet = true;
2366  if (ret == AVERROR(EAGAIN))
2367  ret = 0;
2368  if (ret == 0)
2369  ret = avcodec_send_frame(m_mpaVidCtx, mpa_picture);
2370  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
2371  // there are 2 packets to be received while only 1 frame to be
2372  // sent. The code does not cater for this. Hopefully it will not happen.
2373 
2374  if (ret < 0)
2375  {
2376  std::string error;
2377  LOG(VB_GENERAL, LOG_ERR, LOC + QString("video encode error: %1 (%2)")
2378  .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
2379  av_packet_free(&packet);
2380  return;
2381  }
2382 
2383  if (!got_packet)
2384  {
2385  av_packet_free(&packet);
2386  return;
2387  }
2388 
2389 
2390  tmp = packet->size;
2391  av_packet_free(&packet);
2392  }
2393  }
2394  else
2395  {
2396  int freecount = 0;
2397  freecount = m_actVideoBuffer > m_actVideoEncode ?
2400 
2401  if (freecount < (m_videoBufferCount / 3))
2402  compressthis = 0; // speed up the encode process
2403 
2404  if (freecount < 5)
2405  raw = 1; // speed up the encode process
2406 
2407  if (m_transcoding)
2408  {
2409  raw = 0;
2410  compressthis = 1;
2411  }
2412 
2413  if (!raw)
2414  {
2415  if (wantkeyframe)
2416  m_rtjc->SetNextKey();
2417  tmp = m_rtjc->Compress(m_strm, planes.data());
2418  }
2419  else
2420  tmp = frame->m_bufferSize;
2421 
2422  // here is lzo compression afterwards
2423  if (compressthis)
2424  {
2425  int r = 0;
2426  if (raw)
2427  {
2428  r = lzo1x_1_compress(frame->m_buffer, frame->m_bufferSize,
2429  m_out.data(), &out_len, m_wrkmem.data());
2430  }
2431  else
2432  {
2433  r = lzo1x_1_compress((unsigned char *)m_strm, tmp, m_out.data(),
2434  &out_len, m_wrkmem.data());
2435  }
2436  if (r != LZO_E_OK)
2437  {
2438  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo compression failed");
2439  return;
2440  }
2441  }
2442  }
2443 
2444  frameheader.frametype = 'V'; // video frame
2445  frameheader.timecode = timecode.count();
2446  m_lastTimecode = frameheader.timecode;
2447  frameheader.filters = 0; // no filters applied
2448 
2449  // compr ends here
2450  if (m_useAvCodec)
2451  {
2452  if (m_mpaVidCodec->id == AV_CODEC_ID_RAWVIDEO)
2453  {
2454  frameheader.comptype = '0';
2455  frameheader.packetlength = frame->m_bufferSize;
2456  WriteFrameheader(&frameheader);
2457  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize);
2458  }
2459  else if (m_hardwareEncode)
2460  {
2461  frameheader.comptype = '4';
2462  frameheader.packetlength = frame->m_bufferSize;
2463  WriteFrameheader(&frameheader);
2464  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize);
2465  }
2466  else
2467  {
2468  frameheader.comptype = '4';
2469  frameheader.packetlength = tmp;
2470  WriteFrameheader(&frameheader);
2472  }
2473  }
2474  else if (compressthis == 0 || (tmp < (int)out_len))
2475  {
2476  if (!raw)
2477  {
2478  frameheader.comptype = '1'; // video compression: RTjpeg only
2479  frameheader.packetlength = tmp;
2480  WriteFrameheader(&frameheader);
2482  }
2483  else
2484  {
2485  frameheader.comptype = '0'; // raw YUV420
2486  frameheader.packetlength = frame->m_bufferSize;
2487  WriteFrameheader(&frameheader);
2488  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize); // we write buf directly
2489  }
2490  }
2491  else
2492  {
2493  if (!raw)
2494  frameheader.comptype = '2'; // video compression: RTjpeg with lzo
2495  else
2496  frameheader.comptype = '3'; // raw YUV420 with lzo
2497  frameheader.packetlength = out_len;
2498  WriteFrameheader(&frameheader);
2499  m_ringBuffer->Write(m_out.data(), out_len);
2500  }
2501 
2502  if (m_framesWritten == 0)
2503  SendMythSystemRecEvent("REC_STARTED_WRITING", m_curRecording);
2504 
2505  m_frameOfGop++;
2506  m_framesWritten++;
2507 
2508  // now we reset the last frame number so that we can find out
2509  // how many frames we didn't get next time
2510  m_lf = fnum;
2511 }
2512 
2513 void NuppelVideoRecorder::WriteAudio(unsigned char *buf, int fnum, std::chrono::milliseconds timecode)
2514 {
2515  struct rtframeheader frameheader {};
2516 
2517  if (m_lastBlock == 0)
2518  {
2519  m_firstTc = -1ms;
2520  }
2521 
2522  if (m_lastBlock != 0)
2523  {
2524  if (fnum != (m_lastBlock+1))
2525  {
2526  m_audioBehind = fnum - (m_lastBlock+1);
2527  LOG(VB_RECORD, LOG_INFO, LOC + QString("audio behind %1 %2").
2528  arg(m_lastBlock).arg(fnum));
2529  }
2530  }
2531 
2532  frameheader.frametype = 'A'; // audio frame
2533  frameheader.timecode = timecode.count();
2534 
2535  if (m_firstTc == -1ms)
2536  {
2537  m_firstTc = timecode;
2538 #if 0
2539  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2540  QString("first timecode=%1").arg(m_firstTc.count()));
2541 #endif
2542  }
2543  else
2544  {
2545  timecode -= m_firstTc; // this is to avoid the lack between the beginning
2546  // of recording and the first timestamp, maybe we
2547  // can calculate the audio-video +-lack at the
2548  // beginning too
2549  auto abytes = (double)m_audioBytes; // - (double)m_audioBufferSize;
2550  // wrong guess ;-)
2551  // need seconds instead of msec's
2552  auto mt = (double)timecode.count();
2553  if (mt > 0.0)
2554  {
2555  double eff = (abytes / mt) * (100000.0 / m_audioBytesPerSample);
2556  m_effectiveDsp = (int)eff;
2557  }
2558  }
2559 
2560  if (m_compressAudio)
2561  {
2562  std::array<uint8_t,7200> mp3gapless {};
2563  int compressedsize = 0;
2564  int gaplesssize = 0;
2565  int lameret = 0;
2566 
2567  int sample_cnt = m_audioBufferSize / m_audioBytesPerSample;
2568 
2569 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
2570  auto buf16 = reinterpret_cast<uint16_t *>(buf);
2571  for (int i = 0; i < m_audioChannels * sample_cnt; i++)
2572  buf16[i] = qToLittleEndian<quint16>(buf16[i]);
2573 #endif
2574  if (m_audioChannels == 2)
2575  {
2576  lameret = lame_encode_buffer_interleaved(
2577  m_gf, (short int*) buf, sample_cnt,
2578  (unsigned char*) m_mp3Buf, m_mp3BufSize);
2579  }
2580  else
2581  {
2582  lameret = lame_encode_buffer(
2583  m_gf, (short int*) buf, (short int*) buf, sample_cnt,
2584  (unsigned char*) m_mp3Buf, m_mp3BufSize);
2585  }
2586 
2587  if (lameret < 0)
2588  {
2589  LOG(VB_GENERAL, LOG_ERR, LOC +
2590  QString("lame error '%1'").arg(lameret));
2591  m_error = QString("Audio Encoding Error '%1'")
2592  .arg(lameret);
2593  return;
2594  }
2595  compressedsize = lameret;
2596 
2597  lameret = lame_encode_flush_nogap(m_gf, mp3gapless.data(), mp3gapless.size());
2598  if (lameret < 0)
2599  {
2600  LOG(VB_GENERAL, LOG_ERR, LOC +
2601  QString("lame error '%1'").arg(lameret));
2602  m_error = QString("Audio Encoding Error '%1'")
2603  .arg(lameret);
2604  return;
2605  }
2606  gaplesssize = lameret;
2607 
2608  frameheader.comptype = '3'; // audio is compressed
2609  frameheader.packetlength = compressedsize + gaplesssize;
2610 
2611  if (frameheader.packetlength > 0)
2612  {
2613  WriteFrameheader(&frameheader);
2614  m_ringBuffer->Write(m_mp3Buf, compressedsize);
2615  m_ringBuffer->Write(mp3gapless.data(), gaplesssize);
2616  }
2618  }
2619  else
2620  {
2621  frameheader.comptype = '0'; // uncompressed audio
2622  frameheader.packetlength = m_audioBufferSize;
2623 
2624  WriteFrameheader(&frameheader);
2626  m_audioBytes += m_audioBufferSize; // only audio no header!!
2627  }
2628 
2629  // this will probably never happen and if there would be a
2630  // 'uncountable' video frame drop -> material==worthless
2631  if (m_audioBehind > 0)
2632  {
2633  LOG(VB_RECORD, LOG_INFO, LOC + "audio behind");
2634  frameheader.frametype = 'A'; // audio frame
2635  frameheader.comptype = 'N'; // output a nullframe with
2636  frameheader.packetlength = 0;
2637  WriteFrameheader(&frameheader);
2639  m_audioBehind--;
2640  }
2641 
2642  m_lastBlock = fnum;
2643 }
2644 
2645 void NuppelVideoRecorder::WriteText(unsigned char *buf, int len, std::chrono::milliseconds timecode,
2646  int pagenr)
2647 {
2648  struct rtframeheader frameheader {};
2649 
2650  frameheader.frametype = 'T'; // text frame
2651  frameheader.timecode = timecode.count();
2652 
2653  if (VBIMode::PAL_TT == m_vbiMode)
2654  {
2655  frameheader.comptype = 'T'; // european teletext
2656  frameheader.packetlength = len + 4;
2657  WriteFrameheader(&frameheader);
2658  union page_t {
2659  int32_t m_val32;
2660  struct { int8_t m_a,m_b,m_c,m_d; } m_val8;
2661  } v {};
2662  v.m_val32 = pagenr;
2663  m_ringBuffer->Write(&v.m_val8.m_d, sizeof(int8_t));
2664  m_ringBuffer->Write(&v.m_val8.m_c, sizeof(int8_t));
2665  m_ringBuffer->Write(&v.m_val8.m_b, sizeof(int8_t));
2666  m_ringBuffer->Write(&v.m_val8.m_a, sizeof(int8_t));
2667  m_ringBuffer->Write(buf, len);
2668  }
2669  else if (VBIMode::NTSC_CC == m_vbiMode)
2670  {
2671  frameheader.comptype = 'C'; // NTSC CC
2672  frameheader.packetlength = len;
2673 
2674  WriteFrameheader(&frameheader);
2675  m_ringBuffer->Write(buf, len);
2676  }
2677 }
2678 
2679 /* vim: set expandtab tabstop=4 shiftwidth=4: */
rtframeheader
Definition: format.h:34
NuppelVideoRecorder::m_channelFd
int m_channelFd
Definition: NuppelVideoRecorder.h:278
NuppelVideoRecorder::m_heightMultiplier
double m_heightMultiplier
Definition: NuppelVideoRecorder.h:236
NuppelVideoRecorder::m_q
int m_q
Definition: NuppelVideoRecorder.h:162
extendeddata::version
int version
Definition: format.h:98
NuppelVideoRecorder::m_actAudioBuffer
int m_actAudioBuffer
Definition: NuppelVideoRecorder.h:201
mpeg
Definition: mythchrono.h:51
RecorderBase::SetPositionMapType
void SetPositionMapType(MarkTypes type)
Set seektable type.
Definition: recorderbase.h:279
FOURCC_I263
#define FOURCC_I263
Definition: fourcc.h:96
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:62
rtfileheader::fps
double fps
Definition: format.h:27
NuppelVideoRecorder::FormatCC
void FormatCC(uint code1, uint code2) override
Definition: NuppelVideoRecorder.cpp:2078
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
NuppelVideoRecorder::m_keyframeDist
int m_keyframeDist
Definition: NuppelVideoRecorder.h:222
FILEHEADERSIZE
#define FILEHEADERSIZE
Definition: format.h:140
vbi.h
NuppelVideoRecorder::m_audioChannels
int m_audioChannels
Definition: NuppelVideoRecorder.h:170
teletextsubtitle::row
unsigned char row
Definition: format.h:175
NuppelVideoRecorder::m_audioBits
int m_audioBits
Definition: NuppelVideoRecorder.h:171
vidbuffertype::buffer
unsigned char * buffer
Definition: format.h:149
NuppelVideoRecorder::m_actVideoBuffer
int m_actVideoBuffer
Definition: NuppelVideoRecorder.h:198
NuppelVideoRecorder::m_audioBytes
unsigned long long m_audioBytes
Definition: NuppelVideoRecorder.h:169
NuppelVideoRecorder::StartNewFile
void StartNewFile(void) override
Definition: NuppelVideoRecorder.cpp:2256
NuppelVideoRecorder::StreamAllocate
void StreamAllocate(void)
Definition: NuppelVideoRecorder.cpp:784
V4LRecorder::m_vbiThread
VBIThread * m_vbiThread
Definition: v4lrecorder.h:56
error
static void error(const char *str,...)
Definition: vbi.cpp:36
rtfileheader::height
int height
Definition: format.h:21
FrameRate::toDouble
double toDouble(void) const
Definition: recorderbase.h:41
NuppelVideoRecorder::m_encodingThreadCount
int m_encodingThreadCount
Number of threads to use for MPEG-2 and MPEG-4 encoding.
Definition: NuppelVideoRecorder.h:259
NuppelVideoRecorder::m_clearTimeOnPause
bool m_clearTimeOnPause
Definition: NuppelVideoRecorder.h:275
vidbuffertype::freeToEncode
int freeToEncode
Definition: format.h:147
extendeddata::lavc_maxqdiff
int lavc_maxqdiff
Definition: format.h:117
NuppelVideoRecorder::run
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
Definition: NuppelVideoRecorder.cpp:851
NuppelVideoRecorder::m_videoBuffer
std::vector< struct vidbuffertype * > m_videoBuffer
Definition: NuppelVideoRecorder.h:193
NuppelVideoRecorder::kOutLen
static constexpr size_t kOutLen
Definition: NuppelVideoRecorder.h:188
AudioInput::GetBlockSize
virtual int GetBlockSize(void)=0
NuppelVideoRecorder::m_hmjpgHDecimation
int m_hmjpgHDecimation
Definition: NuppelVideoRecorder.h:271
CC608Decoder::FormatCC
void FormatCC(std::chrono::milliseconds tc, int code1, int code2)
Definition: cc608decoder.cpp:50
NuppelVideoRecorder::m_actTextEncode
int m_actTextEncode
Definition: NuppelVideoRecorder.h:204
NuppelVideoRecorder::m_videoBufferSize
long m_videoBufferSize
Definition: NuppelVideoRecorder.h:211
NuppelVideoRecorder::m_frameOfGop
int m_frameOfGop
Definition: NuppelVideoRecorder.h:242
V4LRecorder
Abstract base class for Video4Linux based recorders.
Definition: v4lrecorder.h:25
NuppelVideoRecorder::Open
bool Open(void)
Definition: NuppelVideoRecorder.cpp:790
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
GO7007IOC_S_COMP_PARAMS
#define GO7007IOC_S_COMP_PARAMS
Definition: go7007_myth.h:91
GO7007_ASPECT_RATIO_4_3_NTSC
@ GO7007_ASPECT_RATIO_4_3_NTSC
Definition: go7007_myth.h:29
NuppelVideoRecorder::AddTextData
void AddTextData(unsigned char *buf, int len, std::chrono::milliseconds timecode, char type) override
Definition: NuppelVideoRecorder.cpp:2089
NuppelVideoRecorder::SetVideoFilters
void SetVideoFilters(QString &filters) override
Tells recorder which filters to use.
Definition: NuppelVideoRecorder.cpp:374
NuppelVideoRecorder::m_wrkmem
std::array< uint8_t, LZO1X_1_MEM_COMPRESS > __LZO_MMODEL m_wrkmem
Definition: NuppelVideoRecorder.h:191
NuppelVideoRecorder::m_usingV4l2
bool m_usingV4l2
Definition: NuppelVideoRecorder.h:277
NuppelVideoRecorder::WriteAudio
void WriteAudio(unsigned char *buf, int fnum, std::chrono::milliseconds timecode)
Definition: NuppelVideoRecorder.cpp:2513
V4LRecorder::m_requestHelper
volatile bool m_requestHelper
Definition: v4lrecorder.h:59
NuppelVideoRecorder.h
NuppelVideoRecorder::m_extendedDataOffset
long long m_extendedDataOffset
Definition: NuppelVideoRecorder.h:226
NuppelVideoRecorder::m_textBuffer
std::vector< struct txtbuffertype * > m_textBuffer
Definition: NuppelVideoRecorder.h:195
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1787
NuppelVideoRecorder::m_hmjpgQuality
int m_hmjpgQuality
Definition: NuppelVideoRecorder.h:270
vt_page::subno
int subno
Definition: vt.h:38
GO7007_COMP_CLOSED_GOP
#define GO7007_COMP_CLOSED_GOP
Definition: go7007_myth.h:45
NuppelVideoRecorder::m_framesWritten
long long m_framesWritten
Definition: NuppelVideoRecorder.h:228
NuppelVideoRecorder::m_seekTable
std::vector< struct seektable_entry > * m_seekTable
Definition: NuppelVideoRecorder.h:223
CC608Decoder
Definition: cc608decoder.h:49
V4LRecorder::OpenVBIDevice
int OpenVBIDevice(void)
Definition: v4lrecorder.cpp:94
MythAVFrame
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythaverror.h:52
go7007_myth.h
go7007_comp_params::max_b_frames
__u32 max_b_frames
Definition: go7007_myth.h:39
NuppelVideoRecorder::m_lastTimecode
int m_lastTimecode
Definition: NuppelVideoRecorder.h:243
rtfileheader::width
int width
Definition: format.h:20
NuppelVideoRecorder::WriteText
void WriteText(unsigned char *buf, int len, std::chrono::milliseconds timecode, int pagenr)
Definition: NuppelVideoRecorder.cpp:2645
VBIData::teletextpage
vt_page teletextpage
Definition: v4lrecorder.h:20
NuppelVideoRecorder::AudioInit
int AudioInit(bool skipdevice=false)
Definition: NuppelVideoRecorder.cpp:631
extendeddata::audio_channels
int audio_channels
Definition: format.h:104
NuppelVideoRecorder::MJPEGInit
bool MJPEGInit(void)
Determines MJPEG capture resolution.
Definition: NuppelVideoRecorder.cpp:707
RecorderBase::m_tvrec
TVRec * m_tvrec
Definition: recorderbase.h:315
DTVRecorder::IsErrored
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:45
FOURCC_HFYU
#define FOURCC_HFYU
Definition: fourcc.h:95
MythMediaBuffer::Write
int Write(const void *Buffer, uint Count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
Definition: mythmediabuffer.cpp:1625
NuppelVideoRecorder::m_audioBytesPerSample
int m_audioBytesPerSample
Definition: NuppelVideoRecorder.h:172
rtfileheader::textsblocks
int textsblocks
Definition: format.h:30
rtfileheader::desiredheight
int desiredheight
Definition: format.h:23
NuppelVideoRecorder::SetupRTjpeg
void SetupRTjpeg(void)
Definition: NuppelVideoRecorder.cpp:497
rtframeheader::timecode
int timecode
Definition: format.h:85
NuppelVideoRecorder::m_writePaused
bool m_writePaused
Definition: NuppelVideoRecorder.h:231
RTjpeg::SetNextKey
void SetNextKey(void)
Definition: RTjpegN.cpp:3261
AudioInput::GetSamples
virtual int GetSamples(void *buf, uint nbytes)=0
seektable_entry
Definition: format.h:127
FMT_YUV422P
@ FMT_YUV422P
Definition: mythframe.h:37
RecorderBase::m_videoWidth
uint m_videoWidth
Definition: recorderbase.h:332
txtbuffertype::freeToEncode
int freeToEncode
Definition: format.h:167
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
VBIMode::None
@ None
Definition: tv.h:11
channelbase.h
NuppelVideoRecorder::ResizeVideoBuffers
void ResizeVideoBuffers(void)
Definition: NuppelVideoRecorder.cpp:775
NuppelVideoRecorder::m_mp4Opts
int m_mp4Opts
Definition: NuppelVideoRecorder.h:256
NuppelVideoRecorder::m_scaleBitRate
int m_scaleBitRate
Definition: NuppelVideoRecorder.h:252
NuppelVideoRecorder::m_v4l2PixelFormat
uint32_t m_v4l2PixelFormat
Definition: NuppelVideoRecorder.h:264
NuppelVideoRecorder::m_audioThread
NVRAudioThread * m_audioThread
Definition: NuppelVideoRecorder.h:218
mythsystemevent.h
NuppelVideoRecorder::SetNewVideoParams
void SetNewVideoParams(double newaspect)
Definition: NuppelVideoRecorder.cpp:1478
V4LRecorder::VBIThread
friend class VBIThread
Definition: v4lrecorder.h:27
go7007_comp_params::gop_size
__u32 gop_size
Definition: go7007_myth.h:38
GO7007_MPEG_VIDEO_MPEG2
@ GO7007_MPEG_VIDEO_MPEG2
Definition: go7007_myth.h:51
NuppelVideoRecorder::m_videoBufferCount
int m_videoBufferCount
Definition: NuppelVideoRecorder.h:207
MythVideoFrame::m_offsets
FrameOffsets m_offsets
Definition: mythframe.h:143
MythVideoFrame::m_forceKey
bool m_forceKey
Definition: mythframe.h:139
NVRWriteThread::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: NuppelVideoRecorder.cpp:83
kfatable_entry
Definition: format.h:133
DTVRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: dtvrecorder.cpp:126
NuppelVideoRecorder::m_mpaVidCodec
const AVCodec * m_mpaVidCodec
Definition: NuppelVideoRecorder.h:248
NuppelVideoRecorder::m_actAudioEncode
int m_actAudioEncode
Definition: NuppelVideoRecorder.h:200
NuppelVideoRecorder::m_targetBitRate
int m_targetBitRate
Definition: NuppelVideoRecorder.h:251
NuppelVideoRecorder::m_mp3Quality
int m_mp3Quality
Definition: NuppelVideoRecorder.h:181
NuppelVideoRecorder::m_mbDecision
int m_mbDecision
Definition: NuppelVideoRecorder.h:257
extendeddata::audio_fourcc
int audio_fourcc
Definition: format.h:100
rtfileheader::desiredwidth
int desiredwidth
Definition: format.h:22
NuppelVideoRecorder::m_oldTc
std::chrono::milliseconds m_oldTc
Definition: NuppelVideoRecorder.h:240
NuppelVideoRecorder::m_textBufferCount
int m_textBufferCount
Definition: NuppelVideoRecorder.h:209
NuppelVideoRecorder::m_compression
int m_compression
Definition: NuppelVideoRecorder.h:166
VBIMode::PAL_TT
@ PAL_TT
Definition: tv.h:12
extendeddata::rtjpeg_chroma_filter
int rtjpeg_chroma_filter
Definition: format.h:112
KEYFRAMEDIST
static constexpr int8_t KEYFRAMEDIST
Definition: NuppelVideoRecorder.h:39
FOURCC_MJPG
#define FOURCC_MJPG
Definition: fourcc.h:97
audbuffertype
Definition: format.h:154
RecorderBase::m_pauseLock
QMutex m_pauseLock
Definition: recorderbase.h:338
close
#define close
Definition: compat.h:43
V4LRecorder::SetOption
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:56
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
VT_WIDTH
#define VT_WIDTH
Definition: vt.h:4
NuppelVideoRecorder::m_audioBufferCount
int m_audioBufferCount
Definition: NuppelVideoRecorder.h:208
rtfileheader
Definition: format.h:16
AudioInput::IsOpen
virtual bool IsOpen(void)=0
FrameRate::isNonzero
bool isNonzero(void) const
Definition: recorderbase.h:42
RecorderBase::m_requestPause
bool m_requestPause
Definition: recorderbase.h:339
GO7007_ASPECT_RATIO_4_3_PAL
@ GO7007_ASPECT_RATIO_4_3_PAL
Definition: go7007_myth.h:30
FMT_NONE
@ FMT_NONE
Definition: mythframe.h:22
NuppelVideoRecorder::m_audioBuffer
std::vector< struct audbuffertype * > m_audioBuffer
Definition: NuppelVideoRecorder.h:194
NuppelVideoRecorder::m_pipMode
int m_pipMode
Definition: NuppelVideoRecorder.h:165
AudioInput::Start
virtual bool Start(void)=0
RecorderBase::m_recordingWait
QWaitCondition m_recordingWait
Definition: recorderbase.h:347
RecorderBase::m_curRecording
RecordingInfo * m_curRecording
Definition: recorderbase.h:335
AudioInput::Open
virtual bool Open(uint sample_bits, uint sample_rate, uint channels)=0
FRAMEHEADERSIZE
#define FRAMEHEADERSIZE
Definition: format.h:139
NuppelVideoRecorder::m_lastBlock
int m_lastBlock
Definition: NuppelVideoRecorder.h:238
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2984
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
rtframeheader::keyframe
char keyframe
Definition: format.h:72
NuppelVideoRecorder::m_startNum
int m_startNum
Definition: NuppelVideoRecorder.h:241
MythMediaBuffer::GetFilename
QString GetFilename(void) const
Definition: mythmediabuffer.cpp:1740
VT_HEIGHT
#define VT_HEIGHT
Definition: vt.h:5
txtbuffertype::buffer
unsigned char * buffer
Definition: format.h:169
NuppelVideoRecorder::m_hmjpgMaxW
int m_hmjpgMaxW
Definition: NuppelVideoRecorder.h:273
go7007_comp_params
Definition: go7007_myth.h:36
programinfo.h
MythVideoFrame::GetBufferSize
static size_t GetBufferSize(VideoFrameType Type, int Width, int Height, int Aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.cpp:412
NuppelVideoRecorder::m_recording
bool m_recording
Definition: NuppelVideoRecorder.h:220
V4LRecorder::CloseVBIDevice
void CloseVBIDevice(void)
Definition: v4lrecorder.cpp:202
mythlogging.h
NuppelVideoRecorder::m_lf
unsigned int m_lf
Definition: NuppelVideoRecorder.h:158
NuppelVideoRecorder::m_maxQuality
int m_maxQuality
Definition: NuppelVideoRecorder.h:253
NVRAudioThread::m_parent
NuppelVideoRecorder * m_parent
Definition: NuppelVideoRecorder.h:67
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
NuppelVideoRecorder::m_actTextBuffer
int m_actTextBuffer
Definition: NuppelVideoRecorder.h:205
hardwareprofile.scan.profile
profile
Definition: scan.py:97
VBIMode::NTSC_CC
@ NTSC_CC
Definition: tv.h:13
NuppelVideoRecorder::m_minQuality
int m_minQuality
Definition: NuppelVideoRecorder.h:254
txtbuffertype
Definition: format.h:163
RecorderBase::AspectChange
void AspectChange(uint aspect, long long frame)
Note a change in aspect ratio in the recordedmark table.
Definition: recorderbase.cpp:740
audbuffertype::timecode
std::chrono::milliseconds timecode
Definition: format.h:157
MythMediaBuffer::WriterSeek
long long WriterSeek(long long Position, int Whence, bool HasLock=false)
Calls ThreadedFileWriter::Seek(long long,int).
Definition: mythmediabuffer.cpp:1672
FOURCC_LAME
#define FOURCC_LAME
Definition: fourcc.h:81
NuppelVideoRecorder::m_gf
lame_global_flags * m_gf
Definition: NuppelVideoRecorder.h:184
MythFile::copy
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
Definition: mythmiscutil.cpp:263
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:24
RTJ_YUV420
@ RTJ_YUV420
Definition: RTjpegN.h:48
AudioInput::GetNumReadyBytes
virtual int GetNumReadyBytes(void)=0
NuppelVideoRecorder::m_mpaVidCtx
AVCodecContext * m_mpaVidCtx
Definition: NuppelVideoRecorder.h:249
MythVideoFrame::m_timecode
std::chrono::milliseconds m_timecode
Definition: mythframe.h:131
GO7007_MPEG_VIDEO_MPEG4
@ GO7007_MPEG_VIDEO_MPEG4
Definition: go7007_myth.h:52
NuppelVideoRecorder::m_mainPaused
bool m_mainPaused
Definition: NuppelVideoRecorder.h:233
NuppelVideoRecorder::m_go7007
bool m_go7007
Definition: NuppelVideoRecorder.h:292
rtfileheader::videoblocks
int videoblocks
Definition: format.h:28
extendeddata::audio_compression_ratio
int audio_compression_ratio
Definition: format.h:107
teletextsubtitle
Definition: format.h:173
V4LRecorder::StopRecording
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:43
rtframeheader::comptype
char comptype
Definition: format.h:43
NuppelVideoRecorder::WriteVideo
void WriteVideo(MythVideoFrame *frame, bool skipsync=false, bool forcekey=false)
Definition: NuppelVideoRecorder.cpp:2275
RecorderBase::m_videoHeight
uint m_videoHeight
Definition: recorderbase.h:331
NuppelVideoRecorder::m_audioPaused
bool m_audioPaused
Definition: NuppelVideoRecorder.h:232
NuppelVideoRecorder::m_mp3Buf
char * m_mp3Buf
Definition: NuppelVideoRecorder.h:182
NVRWriteThread::m_parent
NuppelVideoRecorder * m_parent
Definition: NuppelVideoRecorder.h:56
NuppelVideoRecorder::IsPaused
bool IsPaused(bool holding_lock=false) const override
Returns true iff recorder is paused.
Definition: NuppelVideoRecorder.cpp:364
RecorderBase::ResolutionChange
void ResolutionChange(uint width, uint height, long long frame)
Note a change in video size in the recordedmark table.
Definition: recorderbase.cpp:791
rtfileheader::pimode
char pimode
Definition: format.h:24
vidbuffertype::timecode
std::chrono::milliseconds timecode
Definition: format.h:146
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:129
FrameRate
Definition: recorderbase.h:37
NuppelVideoRecorder::Pause
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
Definition: NuppelVideoRecorder.cpp:352
GO7007_ASPECT_RATIO_16_9_PAL
@ GO7007_ASPECT_RATIO_16_9_PAL
Definition: go7007_myth.h:32
NuppelVideoRecorder::GetVideoFd
int GetVideoFd(void) override
Returns file descriptor of recorder device.
Definition: NuppelVideoRecorder.cpp:388
NuppelVideoRecorder::WriteFrameheader
void WriteFrameheader(rtframeheader *fh)
Definition: NuppelVideoRecorder.cpp:1469
RecorderBase::IsRecordingRequested
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.
Definition: recorderbase.cpp:250
MythVideoFrame::m_bufferSize
size_t m_bufferSize
Definition: mythframe.h:124
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:897
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
RecorderBase::m_ntscFrameRate
bool m_ntscFrameRate
Definition: recorderbase.h:326
FOURCC_WMV1
#define FOURCC_WMV1
Definition: fourcc.h:103
RecorderBase::m_videoFrameRate
double m_videoFrameRate
Definition: recorderbase.h:327
go7007_comp_params::flags
__u32 flags
Definition: go7007_myth.h:41
NuppelVideoRecorder::m_ccd
CC608Decoder * m_ccd
Definition: NuppelVideoRecorder.h:290
NuppelVideoRecorder::GetFramesWritten
long long GetFramesWritten(void) override
Returns number of frames written to disk.
Definition: NuppelVideoRecorder.cpp:383
NuppelVideoRecorder::m_compressAudio
bool m_compressAudio
Definition: NuppelVideoRecorder.h:167
NuppelVideoRecorder::m_pictureFormat
AVPixelFormat m_pictureFormat
Definition: NuppelVideoRecorder.h:262
NuppelVideoRecorder::m_fd
int m_fd
Definition: NuppelVideoRecorder.h:156
AudioInput::Close
virtual void Close(void)=0
NVRAudioThread::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: NuppelVideoRecorder.cpp:90
NuppelVideoRecorder::ResetForNewFile
void ResetForNewFile(void) override
Definition: NuppelVideoRecorder.cpp:2237
NuppelVideoRecorder::m_m2
int m_m2
Definition: NuppelVideoRecorder.h:161
rtfileheader::finfo
char finfo[12]
Definition: format.h:18
MythMediaBuffer::LiveMode
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
Definition: mythmediabuffer.cpp:1799
DTVRecorder::ClearStatistics
void ClearStatistics(void) override
Definition: dtvrecorder.cpp:184
NuppelVideoRecorder::NVRWriteThread
friend class NVRWriteThread
Definition: NuppelVideoRecorder.h:72
NuppelVideoRecorder::m_audioBehind
int m_audioBehind
Definition: NuppelVideoRecorder.h:244
uint
unsigned int uint
Definition: compat.h:81
RecorderBase::m_videocodec
QString m_videocodec
Definition: recorderbase.h:322
RecorderBase::m_positionMap
frm_pos_map_t m_positionMap
Definition: recorderbase.h:359
V4LRecorder::IsHelperRequested
virtual bool IsHelperRequested(void) const
Definition: v4lrecorder.cpp:50
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
RecorderBase::m_containerFormat
AVContainer m_containerFormat
Definition: recorderbase.h:319
NuppelVideoRecorder::m_mp3BufSize
int m_mp3BufSize
Definition: NuppelVideoRecorder.h:183
RecorderBase::m_weMadeBuffer
bool m_weMadeBuffer
Definition: recorderbase.h:317
extendeddata::video_fourcc
int video_fourcc
Definition: format.h:99
RecorderBase::FrameRateChange
void FrameRateChange(uint framerate, uint64_t frame)
Note a change in video frame rate in the recordedmark table.
Definition: recorderbase.cpp:807
rtfileheader::audioblocks
int audioblocks
Definition: format.h:29
FOURCC_RAWA
#define FOURCC_RAWA
Definition: fourcc.h:82
mythmediabuffer.h
RecorderBase::m_positionMapDelta
frm_pos_map_t m_positionMapDelta
Definition: recorderbase.h:360
RecorderBase::m_videodevice
QString m_videodevice
Definition: recorderbase.h:323
FOURCC_MPG4
#define FOURCC_MPG4
Definition: fourcc.h:101
extendeddata::audio_bits_per_sample
int audio_bits_per_sample
Definition: format.h:103
NuppelVideoRecorder::m_useAvCodec
bool m_useAvCodec
Definition: NuppelVideoRecorder.h:246
extendeddata::lavc_bitrate
int lavc_bitrate
Definition: format.h:114
NuppelVideoRecorder::m_tf
int m_tf
Definition: NuppelVideoRecorder.h:159
NuppelVideoRecorder::m_hmjpgVDecimation
int m_hmjpgVDecimation
Definition: NuppelVideoRecorder.h:272
buffers
Definition: freesurround.cpp:50
NuppelVideoRecorder::DoV4L2
void DoV4L2(void)
Definition: NuppelVideoRecorder.cpp:1037
NuppelVideoRecorder::m_actVideoEncode
int m_actVideoEncode
Definition: NuppelVideoRecorder.h:197
NuppelVideoRecorder::SetFormatV4L2
bool SetFormatV4L2(void)
Definition: NuppelVideoRecorder.cpp:947
vidbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:148
GO7007_ASPECT_RATIO_1_1
@ GO7007_ASPECT_RATIO_1_1
Definition: go7007_myth.h:28
RTjpeg
Definition: RTjpegN.h:53
extendeddata::lavc_qmin
int lavc_qmin
Definition: format.h:115
RecorderBase::m_pauseWait
QWaitCondition m_pauseWait
Definition: recorderbase.h:341
MythMediaBuffer::WriterFlush
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
Definition: mythmediabuffer.cpp:1698
RecorderBase::m_ringBuffer
MythMediaBuffer * m_ringBuffer
Definition: recorderbase.h:316
NuppelVideoRecorder::InitBuffers
void InitBuffers(void)
Definition: NuppelVideoRecorder.cpp:713
NuppelVideoRecorder::m_rtjc
RTjpeg * m_rtjc
Definition: NuppelVideoRecorder.h:186
go7007_comp_params::aspect_ratio
enum go7007_aspect_ratio aspect_ratio
Definition: go7007_myth.h:40
GO7007_ASPECT_RATIO_16_9_NTSC
@ GO7007_ASPECT_RATIO_16_9_NTSC
Definition: go7007_myth.h:31
RecorderBase::m_ntsc
bool m_ntsc
Definition: recorderbase.h:325
vidbuffertype::sample
int sample
Definition: format.h:145
GO7007IOC_S_MPEG_PARAMS
#define GO7007IOC_S_MPEG_PARAMS
Definition: go7007_myth.h:87
V4LRecorder::m_vbiMode
int m_vbiMode
Definition: v4lrecorder.h:49
mythmiscutil.h
NuppelVideoRecorder::m_hardwareEncode
bool m_hardwareEncode
Definition: NuppelVideoRecorder.h:269
RTjpeg::SetIntra
int SetIntra(int *key, int *lm, int *cm)
Definition: RTjpegN.cpp:2726
FOURCC_MPG2
#define FOURCC_MPG2
Definition: fourcc.h:100
NuppelVideoRecorder::WriteSeekTable
void WriteSeekTable(void)
Definition: NuppelVideoRecorder.cpp:1647
NuppelVideoRecorder::WriteFileHeader
void WriteFileHeader(void)
Definition: NuppelVideoRecorder.cpp:1496
extendeddata::keyframeadjust_offset
long long keyframeadjust_offset
Definition: format.h:121
NuppelVideoRecorder::WriteKeyFrameAdjustTable
void WriteKeyFrameAdjustTable(const std::vector< struct kfatable_entry > &kfa_table)
Definition: NuppelVideoRecorder.cpp:1682
rtframeheader::filters
char filters
Definition: format.h:75
NuppelVideoRecorder::m_wOut
int m_wOut
Definition: NuppelVideoRecorder.h:266
NuppelVideoRecorder::IsRecording
bool IsRecording(void) override
Tells whether the StartRecorder() loop is running.
Definition: NuppelVideoRecorder.cpp:378
DTVRecorder::m_error
QString m_error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:160
VBIData
Definition: v4lrecorder.h:17
RTjpeg::SetFormat
int SetFormat(const int *fmt)
Definition: RTjpegN.cpp:2692
ProgramInfo::ClearPositionMap
void ClearPositionMap(MarkTypes type) const
Definition: programinfo.cpp:3808
vidbuffertype::forcekey
bool forcekey
Definition: format.h:151
NuppelVideoRecorder::CreateNuppelFile
int CreateNuppelFile(void)
Definition: NuppelVideoRecorder.cpp:1735
cc.h
NuppelVideoRecorder::Initialize
void Initialize(void) override
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
Definition: NuppelVideoRecorder.cpp:574
formatNUV
@ formatNUV
Definition: recordingfile.h:15
NuppelVideoRecorder::m_lastPositionMapPos
long long m_lastPositionMapPos
Definition: NuppelVideoRecorder.h:224
RecorderBase::m_positionMapLock
QMutex m_positionMapLock
Definition: recorderbase.h:358
audbuffertype::sample
int sample
Definition: format.h:156
NuppelVideoRecorder::doAudioThread
void doAudioThread(void)
Definition: NuppelVideoRecorder.cpp:1805
NuppelVideoRecorder::m_stm
Definition: NuppelVideoRecorder.h:215
audbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:159
NuppelVideoRecorder::m_actAudioSample
long long m_actAudioSample
Definition: NuppelVideoRecorder.h:202
NuppelVideoRecorder::m_audioBufferSize
long m_audioBufferSize
Definition: NuppelVideoRecorder.h:212
NuppelVideoRecorder::m_audioDevice
AudioInput * m_audioDevice
Definition: NuppelVideoRecorder.h:168
extendeddata::audio_sample_rate
int audio_sample_rate
Definition: format.h:102
RTjpeg::SetSize
int SetSize(const int *w, const int *h)
Definition: RTjpegN.cpp:2698
RecorderBase::AspectRatio
AspectRatio
Definition: recorderbase.h:244
mythavutil.h
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:142
NuppelVideoRecorder::m_firstTc
std::chrono::milliseconds m_firstTc
Definition: NuppelVideoRecorder.h:239
NuppelVideoRecorder::m_inPixFmt
VideoFrameType m_inPixFmt
Definition: NuppelVideoRecorder.h:261
rtframeheader::packetlength
int packetlength
Definition: format.h:87
NuppelVideoRecorder::BufferIt
void BufferIt(unsigned char *buf, int len=-1, bool forcekey=false)
Definition: NuppelVideoRecorder.cpp:1405
rtfileheader::aspect
double aspect
Definition: format.h:26
extendeddata
Definition: format.h:96
mythcontext.h
FOURCC_MP42
#define FOURCC_MP42
Definition: fourcc.h:98
extendeddata::rtjpeg_quality
int rtjpeg_quality
Definition: format.h:110
NuppelVideoRecorder::m_useBttv
int m_useBttv
Definition: NuppelVideoRecorder.h:176
extendeddata::audio_quality
int audio_quality
Definition: format.h:108
tv_rec.h
FOURCC_MPEG
#define FOURCC_MPEG
Definition: fourcc.h:99
NuppelVideoRecorder::m_effectiveDsp
int m_effectiveDsp
Definition: NuppelVideoRecorder.h:174
NuppelVideoRecorder::m_transcoding
bool m_transcoding
Definition: NuppelVideoRecorder.h:179
NuppelVideoRecorder::ProbeV4L2
void ProbeV4L2(void)
Definition: NuppelVideoRecorder.cpp:815
build_compdb.action
action
Definition: build_compdb.py:9
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:98
NuppelVideoRecorder::SetupAVCodecVideo
bool SetupAVCodecVideo(void)
Definition: NuppelVideoRecorder.cpp:393
NuppelVideoRecorder::m_correctBttv
bool m_correctBttv
Definition: NuppelVideoRecorder.h:285
NuppelVideoRecorder::m_writeThread
NVRWriteThread * m_writeThread
Definition: NuppelVideoRecorder.h:217
NuppelVideoRecorder::WriteHeader
void WriteHeader(void)
Definition: NuppelVideoRecorder.cpp:1532
NuppelVideoRecorder::UpdateResolutions
void UpdateResolutions(void)
Definition: NuppelVideoRecorder.cpp:512
NuppelVideoRecorder::KillChildren
void KillChildren(void)
Definition: NuppelVideoRecorder.cpp:1374
extendeddata::rtjpeg_luma_filter
int rtjpeg_luma_filter
Definition: format.h:111
rtfileheader::version
char version[5]
Definition: format.h:19
NuppelVideoRecorder::m_resetCapture
bool m_resetCapture
Definition: NuppelVideoRecorder.h:293
FOURCC_DIVX
#define FOURCC_DIVX
Definition: fourcc.h:91
FOURCC_H263
#define FOURCC_H263
Definition: fourcc.h:93
NuppelVideoRecorder::m_textBufferSize
long m_textBufferSize
Definition: NuppelVideoRecorder.h:213
StandardSetting
Definition: standardsettings.h:29
ChannelBase::Retune
virtual bool Retune(void)
Definition: channelbase.h:87
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:324
recordingprofile.h
LOC
#define LOC
Definition: NuppelVideoRecorder.cpp:81
VideoFrameType
VideoFrameType
Definition: mythframe.h:20
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
NuppelVideoRecorder::doWriteThread
void doWriteThread(void)
Definition: NuppelVideoRecorder.cpp:2111
NuppelVideoRecorder::m_height
int m_height
Definition: NuppelVideoRecorder.h:164
NuppelVideoRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: NuppelVideoRecorder.cpp:2261
NuppelVideoRecorder::m_volume
int m_volume
Definition: NuppelVideoRecorder.h:288
RTjpegN.h
audbuffertype::buffer
unsigned char * buffer
Definition: format.h:160
NuppelVideoRecorder::m_strm
signed char * m_strm
Definition: NuppelVideoRecorder.h:157
audioinput.h
myth_nice
bool myth_nice(int val)
Definition: mythmiscutil.cpp:656
NuppelVideoRecorder::m_frameRateMultiplier
double m_frameRateMultiplier
Definition: NuppelVideoRecorder.h:235
RecordingProfile
Definition: recordingprofile.h:41
RecorderBase::m_frameRate
FrameRate m_frameRate
Definition: recorderbase.h:333
MythVideoFrame
Definition: mythframe.h:88
seektable_entry::keyframe_number
int keyframe_number
Definition: format.h:130
go7007_mpeg_params
Definition: go7007_myth.h:56
extendeddata::lavc_qmax
int lavc_qmax
Definition: format.h:116
RTjpeg::SetQuality
int SetQuality(int *quality)
Definition: RTjpegN.cpp:2675
V4LRecorder::m_audioDeviceName
QString m_audioDeviceName
Definition: v4lrecorder.h:47
NuppelVideoRecorder::m_videoAspect
float m_videoAspect
Definition: NuppelVideoRecorder.h:177
RecorderBase::m_unpauseWait
QWaitCondition m_unpauseWait
Definition: recorderbase.h:342
NuppelVideoRecorder::SetOption
void SetOption(const QString &opt, int value) override
handles the "wait_for_seqstart" option.
Definition: NuppelVideoRecorder.cpp:162
RecorderBase::CheckForRingBufferSwitch
virtual bool CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
Definition: recorderbase.cpp:351
NuppelVideoRecorder::UpdateSeekTable
void UpdateSeekTable(int frame_num, long offset=0)
Definition: NuppelVideoRecorder.cpp:1719
ccsubtitle
Definition: format.h:183
NuppelVideoRecorder::m_hOut
int m_hOut
Definition: NuppelVideoRecorder.h:267
RTjpeg::Compress
int Compress(int8_t *sp, uint8_t **planes)
Definition: RTjpegN.cpp:3266
NuppelVideoRecorder::FormatTT
void FormatTT(struct VBIData *vbidata) override
Definition: NuppelVideoRecorder.cpp:1914
vt_page::data
unsigned char data[VT_HEIGHT][VT_WIDTH]
Definition: vt.h:43
NuppelVideoRecorder::m_channelObj
ChannelBase * m_channelObj
Definition: NuppelVideoRecorder.h:280
NuppelVideoRecorder::NuppelVideoRecorder
NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
Definition: NuppelVideoRecorder.cpp:97
GO7007IOC_S_BITRATE
#define GO7007IOC_S_BITRATE
Definition: go7007_myth.h:23
AudioInput::CreateDevice
static AudioInput * CreateDevice(const QByteArray &device)
Definition: audioinput.cpp:30
vidbuffertype
Definition: format.h:143
NuppelVideoRecorder::SetOptionsFromProfile
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
Definition: NuppelVideoRecorder.cpp:250
NuppelVideoRecorder::m_skipBtAudio
bool m_skipBtAudio
Definition: NuppelVideoRecorder.h:282
NuppelVideoRecorder::~NuppelVideoRecorder
~NuppelVideoRecorder() override
Definition: NuppelVideoRecorder.cpp:109
NuppelVideoRecorder::NVRAudioThread
friend class NVRAudioThread
Definition: NuppelVideoRecorder.h:73
MythAVUtil::FillAVFrame
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
Definition: mythavutil.cpp:198
audbuffertype::freeToEncode
int freeToEncode
Definition: format.h:158
rtframeheader::frametype
char frametype
Definition: format.h:36
vt_page::pgno
int pgno
Definition: vt.h:38
rtfileheader::keyframedist
int keyframedist
Definition: format.h:31
NuppelVideoRecorder::Reset
void Reset(void) override
Reset the recorder to the startup state.
Definition: NuppelVideoRecorder.cpp:1757
MAX_VIDEO_BUFFERS
static constexpr size_t MAX_VIDEO_BUFFERS
Definition: NuppelVideoRecorder.cpp:1036
FOURCC_RJPG
#define FOURCC_RJPG
Definition: fourcc.h:102
NuppelVideoRecorder::m_out
std::array< lzo_byte, kOutLen > m_out
Definition: NuppelVideoRecorder.h:189
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
txtbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:168
FOURCC_DIV3
#define FOURCC_DIV3
Definition: fourcc.h:90
NuppelVideoRecorder::m_audioSampleRate
int m_audioSampleRate
Definition: NuppelVideoRecorder.h:173
extendeddata::seektable_offset
long long seektable_offset
Definition: format.h:119
MythMediaBuffer::IsOpen
virtual bool IsOpen(void) const =0
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:898
fourcc.h
NuppelVideoRecorder::m_qualDiff
int m_qualDiff
Definition: NuppelVideoRecorder.h:255
RecorderBase::m_requestRecording
bool m_requestRecording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:344
NuppelVideoRecorder::m_width
int m_width
Definition: NuppelVideoRecorder.h:163
millisecondsFromFloat
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
MythVideoFrame::m_buffer
uint8_t * m_buffer
Definition: mythframe.h:120
tv_play.h
NuppelVideoRecorder::m_livetv
bool m_livetv
Definition: NuppelVideoRecorder.h:230
NuppelVideoRecorder::m_m1
int m_m1
Definition: NuppelVideoRecorder.h:160
RecorderBase::SetIntOption
void SetIntOption(RecordingProfile *profile, const QString &name)
Convenience function used to set integer options from a profile.
Definition: recorderbase.cpp:199