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