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